【问题标题】:Best way to query a Many to Many Relationship using pg-promise使用 pg-promise 查询多对多关系的最佳方法
【发布时间】:2016-08-03 20:18:06
【问题描述】:

例如,我想从 db 中获取用户信息、电子邮件和它的角色,并创建一个像这样的对象:

{
  "id": 1,
  "firstname": "John",
  "lastname": "Johnny",
  "emails": [
    {
      "type": "work",
      "email": "work@work.com"
    },
    {
      "type": "personal",
      "email": "personal@personal.com"
    }
  ],
  "roles": [
    {
      "role": "ADM",
      "title": "Admin"
    },
    {
      "role": "PUB",
      "title": "Publisher"
    }
  ]
}

我需要查询三个表:

  • Users 表有idfirstnamelastname
  • Emails 表有typeemailuser_id
  • Roles 表有roletitleuser_id

基于pg-promise 的wiki,我几乎可以肯定必须使用Tasks 来完成,但不确定您将如何链接它们。

更新 在我的实际项目中,我必须插入一个产品并使用生成的 id 来插入属性。在这里添加我的代码以防您遇到类似情况:

//Insert a new product with attribites as key value pairs
post_product_with_attr: function(args) {
    return db.task(function(t) {
        return t.one(sql.post_new_product, args)
            .then(function(dt) {
                var queries = [];
                Object.keys(args).forEach(function(key) {
                    queries.push(t.one(sql.post_attr_one, { Id: dt.id, key: key, value: args[key] }));
                 });
                return queries.length ? t.batch(queries) : [dt];
            });
    });
}

【问题讨论】:

  • 当一个查询的参数是前一个查询的结果时,您链接查询,而在您的示例中并非如此。您的示例在查询结果之间没有依赖关系。不需要链接。
  • @vitaly-t,是的,我在这个问题上犯了一个错误。我的实际情况是我有电子邮件,需要先从电子邮件表中获取 user_id。
  • @vitaly-t,我刚刚添加的更新是否看起来不合适,它添加产品并返回 id,但使用调试器我在 pg- 处收到 Loose request outside an expired connection. 的异步错误promise/lib/query.js 第 183 行 reject(errMsg);
  • 是的,(queries > 0) 是一段无效的代码。应该是(queries.length > 0),或者简单地说:return queries.length? t.batch(queries) : [dt];。这就是它在那里失败的原因,因为你永远不会执行t.batch(queries)
  • @vitaly-t,就是这样!谢谢!我什至不确定它最初是怎么变成这样的。大声笑

标签: node.js postgresql express pg-promise


【解决方案1】:

您所描述的不是多对多关系,而是两个一对多关系。

根据 pg-promise 的 wiki,我几乎可以肯定必须使用 Tasks 来完成,但不确定如何将它们链接起来。

在您的示例中,无需链接任何内容。当一个链的结果需要用作下一个链的标准时,一个链承诺,因为这就是承诺的工作方式,而不仅仅是查询。

因此,您可以并行或独立执行所有 3 个查询,如下例所示:

function getUserInfo(userId) {
    return db.task(async t => {
        const user = await t.one('SELECT id, firstname, lastname FROM Users WHERE id = $1', userId);
        const emails = await t.any('SELECT type, email FROM emails WHERE user_id = $1', userId),
        const roles = await t.any('SELECT role, title FROM roles WHERE user_id = $1', userId);

        user.emails = emails;
        user.roles = roles;

        return user;
});

使用示例:

const user = await getUserInfo(123); //=> user object with all details

请注意,通过现有的 PostgreSQL JSON 函数执行此操作会更有效,这样您就可以只执行一个查询。

【讨论】:

  • 谢谢!如果我有用户名并且必须先查询用户表才能从中获取 id,你能告诉我该怎么做吗?
  • @Parham 这有什么帮助吗? - github.com/vitaly-t/pg-promise/blob/master/examples/…
  • 是的,我认为应该可以。谢谢。有机会我会尽快尝试并更新。
  • 嘿,是的,它做到了!谢谢!我会尽快发布我的代码版本。
  • 为了简单起见,更新了答案,使用新的async 语法。
猜你喜欢
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
  • 2021-11-02
  • 2012-02-28
  • 2019-02-11
相关资源
最近更新 更多