【问题标题】:MongoDB, Mongoose results from one Find to search another collectionMongoDB,Mongoose 结果来自一个 Find 来搜索另一个集合
【发布时间】:2016-03-24 21:25:46
【问题描述】:

我知道这违背了 MongoDB 的设计及其 No-SQL 模型,但我试图在一个集合中查找文档,然后使用结果中的 ID 字段来查找另一个集合中的相应记录。有效地尝试模拟连接。

//query is irrelevant to question
var results = collectionOne.find(query).limit(limit);

var a = [];

results.forEach(function(r)
{
    var aquery = { id : {$eq : r.id}};
    collectionTwo.find(aquery).limit(limit).exec(function, b)
    {
        if (err)
        {
            res.render('error',
            {
                status :  500
            });
        }
        else
        {
            a.push(b);
        }
   });
});
res.jsonp(a);

【问题讨论】:

  • 你可以使用聚合和 $lookup 来执行这个服务器端

标签: node.js mongodb mongoose mongodb-query


【解决方案1】:

虽然 MongoDB 中有一些新功能,例如 $lookup,它会执行“某种连接”,但您的特定操作不需要这个。您在这里所做的只是根据 _id 值与前一个集合的匹配位置从另一个集合返回结果。

为此,最好的选择是使用$in 对另一个集合发出一个更多查询。

// Mongoose turns a cursor to an array by default in the callback method
collectionOne.find(query,{ "_id": 1}).limit(limit).exec(function(err,results) {

    // Just get array of _id values
    var ids = results.map(function(el) { return el._id } );

    // Not sure if you really mean both collections have the same primary key
    // I'm presuming two different fields being "id" as opposed to "_id"
    collectionTwo.find({ "id": { "$in": ids } },function(err,items) {
       // matching results are here
    })

})

就是这样。

您所做的只是将_id 值的第一个查询结果作为“列表”返回,然后将该参数提供给目标集合中相关字段的$in

如果你真的想要一个“加入”并且有可用的 MongoDB 3.2,那么你可以像这样使用$lookup

collectionOne.aggregate([
    { "$match": query },
    { "$limit": limit },
    { "$lookup": {
        "from": "collectionTwo",
        "localField": "_id",
        "foreignField": "id",
        "as": "twoItems"
    }}
])

这是一个实际的“加入”结果,虽然您可以可能使用它从collectionTwo 返回匹配的结果,但我个人不会。即使在服务器上,这也是一项昂贵的练习,并且进一步过滤实际返回该格式所需的操作最终会花费更多。

您还可能会在 mongoose 中读到有关 .populate() 的信息,这实际上是此类查询的“反向”。相反,它的过程是存储ObjectId 值的数组(或常规字段,在这种情况下为数组),指向相关集合中对象的主键。因此,如果 collectionTwo 有“许多”值,那么这些值将存储在 collectionOne 文档中的数组中。

同样,这是一个“连接仿真”,而不是真正的连接。结果与$lookup 相似,而且不是真正“只是”来自collectionTwo 的结果,而是“加入”版本,您同样需要过滤。

.populate() 真正发生的所有事情是它无论如何都会运行$in 查询。因此,即使在完成了将子引用存储在父级中的所有工作(恕我直言,在大多数情况下,如果你能做到这一点,那么你也可以只嵌入数据),与数据库的实际交互仍然保持不变,因为它仍然执行$in 查询。

【讨论】:

  • @user3424480 不确定你认为你的意思。如果您的意思是当“源”使用ObjectId 时,“目标”也必须使用,那么当然可以。这对于任何 BSON 类型都是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多