使用pg-promise查询多对多关系的最佳方法

时间:2016-04-13 00:34:58

标签: node.js postgresql express pg-promise

例如,我想从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来完成,但不确定如何将它们链接起来。

UPDATE 在我的实际项目中,我必须插入一个产品并使用生成的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];
            });
    });
}

1 个答案:

答案 0 :(得分:1)

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

  

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

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

因此,您可以批量并行执行所有3个查询。

以下示例使用pg-promiseBluebird作为承诺库:

function getUserInfo(userId) {
    return db.task(t=>t.batch([
            t.one('SELECT id, firstname, lastname FROM Users WHERE id = $1', userId),
            t.any('SELECT type, email FROM Emails WHERE user_id = $1', userId),
            t.any('SELECT role, title FROM Roles WHERE user_id = $1', userId)
        ]))
        .spread((user, emails, roles)=> {
            user.emails = emails;
            user.roles = roles;
            return user;
        })
}

用法示例:

getUserInfo(123)
    .then(info=> {
        // info = object as described in the question;
    })
    .catch(error=> {
        // error;
    });