4

我使用该pg-promisebluebird进行相关查询。我有两个表,a 和 b,看起来像这样:

|   a   |     |   b   |  
|-------|     |-------|
| a_id  |     | b_id  |
| prop1 |     | prop2 |
              |  b_a  |

哪里b.b_a是对 的引用a.a_id。我想选择与给定匹配的所有条目prop1,结果应包含所有匹配a的 -rows 加上b每个对应的 -rows 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;
            });
    });
}

而且我还能够为多个-results获得所有匹配b的 -entries,如下所示: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
            });
    });
}

但是如何将这两者结合在一起呢?

4

1 回答 1

4

我是pg-promise的作者。


当您有 2 个表时:Parent->Child具有一对多关系,并且您想要获取匹配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(a => t.batch(a))
})
    .then(data => {
        /* data = the complete tree */
    });

这就是我们在那里所做的:

首先,我们查询Parent项目,然后我们将每一行映射到相应Child项目的查询中,然后将其行设置到Parent并返回它。然后我们使用方法批处理Child来解析从方法map返回的查询数组。

ES7 更新

这里和上面一样,但是使用 ES7 async/await语法:

await db.task(async t => {
    const parents = await t.any('SELECT * FROM Parent WHERE prop1 = $1', [prop1]);
    for(const p of parents) {
        p.children = await t.any('SELECT * FROM Child WHERE parentId = $1', [p.id]);
    }
    return parents;
});
// the task resolves with the correct data tree

该任务将使用如下数组解决:

[
    {
        "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"}
        ]
    }    
]

API 参考:地图批处理

更新

请参阅对此的更好答案:JOIN table as array of results with PostgreSQL/NodeJS

于 2016-06-06T22:12:09.843 回答