Mongoose - 从多个集合中查询

时间:2017-05-22 15:41:19

标签: javascript node.js mongodb mongoose

对于NoSQL来说,我是一个新手,所以在使用MongoDB学习它的过程中,我决定制作一个Help Desk应用程序。现在,设计数据模型,我有用户和票据,我建模如下。

User
----
 |- mid  (member id, String)
 |- name (user name, String)
 |- mail (e-mail, String)
 \_ pass (md5 hashed password, String)

我正在尝试使用引用来跟踪它,故障单将引用创建它们的用户以及回复故障单的用户。我的结构如下:

Ticket
------
  |- tid      (ticket id, String)
  |- title    (title of ticket, String)
  |- status   (status of ticket, String)
  |- replies  (embedded replies doc, [{ mid: ..., msg: ... }])
  |- assignee (whom the topic is assigned to, String, refers to users)
  \_ priority (priority level of the ticket, 1-5, Number)

现在我想向用户显示所有打开的门票的列表;通过以下方式:

| Title                  | Num Replies | Assignee | Author | Priority |
|------------------------|-------------|----------|--------|----------|
| Unblock this URL       | 5           | SHC      | ABC    |        5 |
| Install MS Office here | 2           | STC      | XYZ    |        4 |
                                 ...

我只是用以下代码获取所有打开的门票:

tickets.find({ "status": "open" }, (err, data) =>
{
    if (err)
    {
        console.error(err);
        res.json({
            "success": false,
            "message": "Failure to get from database"
        });
    }
    else
    {
        // TODO: Convert the "mid" references in the data
    }
});

这看起来很简单到现在为止,但data这里是一系列打开的门票,authorassignee的字段作为成员ID,我需要名称成员。

我当然可以做另一个查询来查找会员名称,但假设有100张打开的门票,那将会得到201个查询,这并不酷。

我确实试图优化这个东西,并通过创建一个不同用户数组,使用$in查询从数据库中获取用户对象然后循环所有票证并使用获得的结果来解决这个问题。将它们映射到服务器中,使其只有2个查询。它有效,但我想知道如何正确处理它而不是任何黑客攻击。

来自MySQL背景,我会在MySQL的单个查询中完成此任务:

select t.tid, t.title, t.priority, a1.name, a2.name
    from tickets t, users a1, users a2
    where a1.mid = t.assignee and
          a2.mid = t.author;

我应该如何使用Mongoose在MongoDB中处理这种查询?

2 个答案:

答案 0 :(得分:1)

你的MySQL查询使用了一个联接 - 正如你所发现的那样,mongodb不支持。

您有几种选择,其中一种已经提供过。

  

创建不同用户的数组,从中获取用户对象   数据库使用$ in查询然后循环遍历所有票证和   使用获得的结果将它们映射到服务器中,使其仅为2   查询

......对我来说听起来不好。

其次,正在使用populate - http://mongoosejs.com/docs/populate.html

您需要将ticket架构更改为:

var ticketSchema = Schema({
  assignee : { type: String, ref: 'User' },
  title    : String,
  //etc...
});

然后,调用populate:

tickets.find({ "status": "open" })
    .populate('assignee')
    .exec(err, data) =>
    {
        if (err)
        {
            console.error(err);
            res.json({
                "success": false,
                "message": "Failure to get from database"
            });
        }
        else
        {
            // TODO: Convert the "mid" references in the data
        }
    });

注意,在幕后,这实际上是包装多个查询 - 但不要惊慌 - 这是NoSQL的公认权衡。

如果你的" hacky"方式是有效的,我建议坚持下去 - 它不是真正的黑客,只是缺乏JOIN的解决方法。

答案 1 :(得分:0)

您正在寻找populate(...)方法,该方法允许您插入您之后的相关对象(用户)而不是mid

http://mongoosejs.com/docs/populate.html