MongoDB,Mongoose从一个Find中search另一个集合

我知道这是违反了MongoDB和它的无SQL模型的devise,但我试图在一个集合中查找文档,然后使用结果中的ID字段查找另一个集合中的相应logging。 有效地尝试模拟连接。

//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); 

虽然MongoDB中有一些新function,例如$lookup ,它可以进行“连接sorting”,但您的具体操作并不需要这些function。 你在这里所做的是从另一个集合中返回结果,这个结果是根据_id值从前一个集合中被调整的地方得到的。

为此,最好的select是使用$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在目标集合的相关字段上

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

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

这是一个真正的“join”结果,虽然你可能用它来从collectionTwo返回匹配的结果,但是我个人不会。 即使在服务器上也是昂贵的练习,而进一步过滤需要实际返回该格式的操作将最终花费更多。

你也可以在mongoose中读到关于.populate() ,这实际上是这种types的查询的“反向”。 相反,它的过程是存储指向相关集合中对象的主键的ObjectId值的数组(或本例中的常规字段,但数组)。 因此,如果collectionTwo有多个“值”,那么这些值将被存储在collectionOne文档中的一个数组中。

再次,这是一个“join模拟”,而不是一个真正的联接。 结果将类似于$lookup ,并且再也不是真正的“just”来自collectionTwo的结果,而是“joined”版本,您将同样需要过滤。

所有与.populate()真正发生的事情是它运行一个$in查询无论如何。 所以,即使在父级(IMHO,在大多数情况下,如果你可以做到这一点,然后你可能只是embedded数据)的父级存储子引用的工作,与数据库的实际交互保持不变,因为它仍然$in查询中。