$在数组中的ObjectId上查找

对一个ObjectId数组的字段进行$ lookup的语法是什么,而不仅仅是一个ObjectId?

示例订单文档:

{ _id: ObjectId("..."), products: [ ObjectId("..<Car ObjectId>.."), ObjectId("..<Bike ObjectId>..") ] } 

不工作查询:

 db.orders.aggregate([ { $lookup: { from: "products", localField: "products", foreignField: "_id", as: "productObjects" } } ]) 

期望的结果

 { _id: ObjectId("..."), products: [ ObjectId("..<Car ObjectId>.."), ObjectId("..<Bike ObjectId>..") ], productObjects: [ {<Car Object>}, {<Bike Object>} ], } 

$lookup聚合pipe道阶段不会直接与数组一起工作。 devise的主要目的是将“左连接”作为“一对多”types的连接(或者真正的“查找”)在可能的相关数据上。 但价值是为了单数,而不是一个数组。

因此,在执行$lookup操作之前,您必须首先对内容“取消规范化”,以使其正常工作。 这意味着使用$unwind

 db.orders.aggregate([ // Unwind the source { "$unwind": "$products" }, // Do the lookup matching { "$lookup": { "from": "products", "localField": "products", "foreignField": "_id", "as": "productObjects" }}, // Unwind the result arrays ( likely one or none ) { "$unwind": "$productObjects" }, // Group back to arrays { "$group": { "_id": "$_id", "products": { "$push": "$products" }, "productObjects": { "$push": "$productObjects" } }} ]) 

$lookup匹配每个数组成员后,结果是一个数组本身,所以你$unwind再次和$group$push新arrays的最终结果。

请注意,没有find的任何“左连接”匹配将为给定产品上的“productObjects”创build一个空数组,从而在调用第二个$unwind时否定“product”元素的文档。

虽然对数组的直接应用会很好,但是通过将奇异值与可能的数值进行匹配,这就是目前的工作方式。

由于$lookup基本上是非常新的,现在它熟悉那些熟悉mongoose的人们熟悉的.populate()方法提供的“穷人版本”。 不同之处在于, $lookup提供了“join”的“服务器端”处理,而不是客户端, $lookup中的一些“成熟”目前缺乏.populate()提供的内容(比如插入查找直接在一个数组上)。

这实际上是改进SERVER-22881的一个指定问题,所以如果运气好一点,这会在下一个版本或者之后的版本中出现。

作为一个devise原则,你当前的结构既不好也不坏,但是在创build任何“连接”的时候,只是需要开销。 因此,MongoDB在开始阶段的基本原则是适用的,如果您可以在一个集合中“预join”数据,那么最好这样做。

另一个可以说是$lookup作为一般原则的事情是,这里的“join”的意图是反过来工作,而不是在这里显示。 因此,与其他文件的“相关标识”保存在“母”文件中不同的是,最有效的一般原则是“相关文件”包含对“母”的引用。

所以$lookup可以说是“最好的”与“关系devise”是相反的如何像mongoose.populate()执行它的客户端连接。 通过标识每个“多”中的“一个”,然后只需拉入相关的项目,而不需要先退出数组。

$lookup聚合pipe道阶段现在直接与一个数组(3.3.4版本)。

请参阅: 在本地(多个)数组值和外部(单个)值之间查找

使用$展开你会得到第一个对象,而不是数组的对象

查询:

 db.getCollection('vehicles').aggregate([ { $match: { status: "AVAILABLE", vehicleTypeId: { $in: Array.from(newSet(d.vehicleTypeIds)) } } }, { $lookup: { from: "servicelocations", localField: "locationId", foreignField: "serviceLocationId", as: "locations" } }, { $unwind: "$locations" } ]); 

结果:

 { "_id" : ObjectId("59c3983a647101ec58ddcf90"), "vehicleId" : "45680", "regionId" : 1.0, "vehicleTypeId" : "10TONBOX", "locationId" : "100", "description" : "Isuzu/2003-10 Ton/Box", "deviceId" : "", "earliestStart" : 36000.0, "latestArrival" : 54000.0, "status" : "AVAILABLE", "accountId" : 1.0, "locations" : { "_id" : ObjectId("59c3afeab7799c90ebb3291f"), "serviceLocationId" : "100", "regionId" : 1.0, "zoneId" : "DXBZONE1", "description" : "Masafi Park Al Quoz", "locationPriority" : 1.0, "accountTypeId" : 0.0, "locationType" : "DEPOT", "location" : { "makani" : "", "lat" : 25.123091, "lng" : 55.21082 }, "deliveryDays" : "MTWRFSU", "timeWindow" : { "timeWindowTypeId" : "1" }, "address1" : "", "address2" : "", "phone" : "", "city" : "", "county" : "", "state" : "", "country" : "", "zipcode" : "", "imageUrl" : "", "contact" : { "name" : "", "email" : "" }, "status" : "", "createdBy" : "", "updatedBy" : "", "updateDate" : "", "accountId" : 1.0, "serviceTimeTypeId" : "1" } } { "_id" : ObjectId("59c3983a647101ec58ddcf91"), "vehicleId" : "81765", "regionId" : 1.0, "vehicleTypeId" : "10TONBOX", "locationId" : "100", "description" : "Hino/2004-10 Ton/Box", "deviceId" : "", "earliestStart" : 36000.0, "latestArrival" : 54000.0, "status" : "AVAILABLE", "accountId" : 1.0, "locations" : { "_id" : ObjectId("59c3afeab7799c90ebb3291f"), "serviceLocationId" : "100", "regionId" : 1.0, "zoneId" : "DXBZONE1", "description" : "Masafi Park Al Quoz", "locationPriority" : 1.0, "accountTypeId" : 0.0, "locationType" : "DEPOT", "location" : { "makani" : "", "lat" : 25.123091, "lng" : 55.21082 }, "deliveryDays" : "MTWRFSU", "timeWindow" : { "timeWindowTypeId" : "1" }, "address1" : "", "address2" : "", "phone" : "", "city" : "", "county" : "", "state" : "", "country" : "", "zipcode" : "", "imageUrl" : "", "contact" : { "name" : "", "email" : "" }, "status" : "", "createdBy" : "", "updatedBy" : "", "updateDate" : "", "accountId" : 1.0, "serviceTimeTypeId" : "1" } } 

$lookup和随后的$group聚合非常麻烦,所以如果(并且这是一个中等的)你使用node&Mongoose或者在模式中有一些提示的支持库,你可以使用.populate()来获取这些文件:

 var mongoose = require("mongoose"), Schema = mongoose.Schema; var productSchema = Schema({ ... }); var orderSchema = Schema({ _id : Number, products: [ { type: Schema.Types.ObjectId, ref: "Product" } ] }); var Product = mongoose.model("Product", productSchema); var Order = mongoose.model("Order", orderSchema); ... Order .find(...) .populate("products") ...