我使用pg-promise
库与bluebird
进行相关查询。我有两个表,a和b,看起来像这样:
| a | | b |
|-------| |-------|
| a_id | | b_id |
| prop1 | | prop2 |
| b_a |
其中b.b_a
是对a.a_id
的引用。我想选择匹配给定prop1
的所有条目,结果应包含所有匹配的a
行以及每个b
的相应a
行。这应该适用于两个相关查询。两个查询都可能返回多个结果。
如果表a
只返回一行,我可以这样做:
function getResult(prop1) {
return db.task(function (t) {
return t.one("select * from a where prop1=$1", prop1)
.then(function (a) {
return t.batch([a, t.any("select * from b where b_a=$1", a.a_id)]);
})
.then(function (data) {
var a = data[0];
var bs = data[1];
bs.forEach(function (b) {
b.a = a;
});
return bs;
});
});
}
而且我也能够获得所有匹配的b
条目,用于多个a
结果,如下所示:
function getResult(prop1) {
return db.task(function (t) {
return t.many("select * from a where prop1=$1", prop1)
.then(function (as) {
var queries = [];
as.forEach(function (a) {
queries.push(t.any("select * from b where b_a=$1", a.id));
});
return t.batch(queries); // could concat queries with as here, but there wouldn't be a reference which b row belongs to which a row
})
.then(function (data) {
// data[n] contains all matching b rows
});
});
}
但是如何将这两者结合在一起?
我是pg-promise的作者。
如果你有2个表:Parent
- > Child
与1对多关系,你想得到一个匹配的Parent
行数组,每行扩展属性children
设置为表Child
对应行的数组...
有几种方法可以实现这一点,因为pg-promise和promises的组合通常非常灵活。这是最短的版本:
db.task(t => {
return t.map('SELECT * FROM Parent WHERE prop1 = $1', [prop1], parent => {
return t.any('SELECT * FROM Child WHERE parentId = $1', parent.id)
.then(children => {
parent.children = children;
return parent;
});
}).then(t.batch) /* this is short for: data => t.batch(data) */
})
.then(data => {
/* data = the complete tree */
});
这就是我们在那里做的事情:
首先,我们查询Parent
项目,然后我们将每一行映射到相应的Child
项目的查询中,然后将其行设置为Parent
并返回它。然后我们使用方法batch来解析从方法Child
返回的map查询数组。
该任务将使用如下数组解决:
[
{
"parent1-prop1", "parent1-prop2",
"children": [
{"child1-prop1", "child1-prop2"},
{"child2-prop1", "child2-prop2"}
]
},
{
"parent2-prop1", "parent2-prop2",
"children": [
{"child3-prop1", "child3-prop2"},
{"child4-prop1", "child4-prop2"}
]
}
]
UPDATE
看到更好的答案:JOIN table as array of results with PostgreSQL/NodeJS。