$在数组中的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") ...