来自外部集合的项目特定字段$查找结果
我正在写聚合,以获得与本地收集外国收集数据。
db.getCollection('orders').aggregate([ { $match: { status: "UNASSIGNED", serviceLocationId: "83177" } }, { $lookup: { from: "servicelocations", localField: "serviceLocationId", foreignField: "serviceLocationId", as: "locations" } }, { $unwind: "$locations" }])
我越来越:
{ "_id" : ObjectId("59d32b5c360198e441b67545"), "accountId" : 1.0, "orderId" : "AQ137O1701240", "serviceLocationId" : "83177", "orderDate" : "2017-09-18T18:29:00.000Z", "description" : "AQ137O1701240", "serviceType" : "Delivery", "orderSource" : "Import", "takenBy" : "KARIM", "plannedDeliveryDate" : ISODate("2017-10-09T00:00:00.000Z"), "plannedDeliveryTime" : "", "actualDeliveryDate" : "", "actualDeliveryTime" : "", "deliveredBy" : "", "size1" : 25.0, "size2" : 464.0, "size3" : 46.0, "jobPriority" : 1.0, "cancelReason" : "", "cancelDate" : "", "cancelBy" : "", "reasonCode" : "", "reasonText" : "", "status" : "UNASSIGNED", "lineItems" : [ { "ItemId" : "MMGW001", "size1" : 25.0, "size2" : 464.38, "size3" : 46.875 } ], "locations" : { "_id" : ObjectId("59ce18e172dbf6926093e189"), "accountId" : 1.0, "serviceLocationId" : "83177", "regionId" : "1", "zoneId" : "DXBZONE1", "description" : "EXPRESS BLUE MART SUPERMARKET", "locationPriority" : 1.0, "accountTypeId" : 1.0, "locationType" : "SERVICELOCATION", "location" : { "makani" : "", "lng" : 55.179042, "lat" : 25.098741 }, "deliveryDays" : "MTWRFSU", "serviceTimeTypeId" : "1", "timeWindow" : { "timeWindowTypeId" : "1" }, "address1" : "", "address2" : "", "phone" : "", "city" : "", "county" : "", "state" : "", "country" : "", "zipcode" : "", "imageUrl" : "", "contact" : { "name" : "", "email" : "" }, "status" : "ACTIVE", "createdBy" : "", "updatedBy" : "", "updateDate" : "" } }
但是我需要:
{ "_id" : ObjectId("59d32b5c360198e441b67545"), "accountId" : 1.0, "orderId" : "AQ137O1701240", "serviceLocationId" : "83177", "orderDate" : "2017-09-18T18:29:00.000Z", "description" : "AQ137O1701240", "serviceType" : "Delivery", "orderSource" : "Import", "takenBy" : "KARIM", "plannedDeliveryDate" : ISODate("2017-10-09T00:00:00.000Z"), "plannedDeliveryTime" : "", "actualDeliveryDate" : "", "actualDeliveryTime" : "", "deliveredBy" : "", "size1" : 25.0, "size2" : 464.0, "size3" : 46.0, "jobPriority" : 1.0, "cancelReason" : "", "cancelDate" : "", "cancelBy" : "", "reasonCode" : "", "reasonText" : "", "status" : "UNASSIGNED", "lineItems" : [ { "ItemId" : "MMGW001", "size1" : 25.0, "size2" : 464.38, "size3" : 46.875 } ], "locations" : { "lng" : 55.179042, "lat" : 25.098741 } }
MongoDB小于3.4.4
基本上,使用$project
作为最后阶段,并select所有你想要的特定领域。 不幸的是, $addFields
已经出来了,因为它实际上是将子键与现有子键“合并”的。 所以看似简单:
{ "$addFields": { "locations": { "lng": "$locations.location.lng", "lat": "$locations.location.lat" } }}
只是给你所有"locations"
下的现有内容以及那些新定义的密钥。 除非你$unwind
$lookup
之后没有直接$unwind
,如果这不会导致BSON限制被超过 ,你可以这样做。 (这叫做$lookup
+ $unwind
coalescence)
然后我们可以使用$addFields
和$map
,因为我们可以简单地“重新映射”数组:
{ "$addFields": { "locations": { "$map": { "input": "$locations", "as": "l", "in": { "lng": "$$l.location.lng", "lat": "$$l.location.lat" } } } }}, { "$unwind": "$locations" }
然后$unwind
如果你仍然需要重新映射。
所以与$project
是这样的:
{ "$project": { "accountId" : 1, "orderId" : 1, "serviceLocationId" : 1, "orderDate" : 1, "description" : 1, "serviceType" : 1, "orderSource" : 1, "takenBy" : 1, "plannedDeliveryDate" : 1, "plannedDeliveryTime" : 1, "actualDeliveryDate" : 1, "actualDeliveryTime" : 1, "deliveredBy" : 1, "size1" : 1, "size2" : 1, "size3" : 1, "jobPriority" : 1, "cancelReason" : 1, "cancelDate" : 1, "cancelBy" : 1, "reasonCode" : 1, "reasonText" : 1, "status" : 1, "lineItems" : 1, "locations" : { "lng": "$locations.location.lng", "lat": "$locations.location.lat" } }}
简单但漫长的啰嗦。
MongoDB 3.4.4或更高版本
如果你有$arrayToObject
和$arrayToObject
MongoDB 3.4.4或更高$arrayToObject
,那么你可以更喜欢它:
{ "$replaceRoot": { "newRoot": { "$arrayToObject": { "$concatArrays": [ { "$filter": { "input": { "$objectToArray": "$$ROOT" }, "cond": { "$ne": [ "$$this.k", "locations" ] } }}, { "$objectToArray": { "locations": { "lng": "$locations.location.lng", "lat": "$locations.location.lat" } }} ] } } }}
它基本上从$$ROOT
到整个文档中的所有字段,将其转换为数组格式。 然后,我们通过“键名” $filter
"location"
字段, $concatArrays
它与新的"location"
键和子键再次转换成一个数组。
最后当然$arrayToObject
把它取回并转换成一个提供给$replaceRoot
作为最终输出的对象。
所以在$addFields
之后使用$addFields
之外的任何一个当然会给你正确的结果:
/* 1 */ { "_id" : ObjectId("59d32b5c360198e441b67545"), "accountId" : 1.0, "orderId" : "AQ137O1701240", "serviceLocationId" : "83177", "orderDate" : "2017-09-18T18:29:00.000Z", "description" : "AQ137O1701240", "serviceType" : "Delivery", "orderSource" : "Import", "takenBy" : "KARIM", "plannedDeliveryDate" : ISODate("2017-10-09T00:00:00.000Z"), "plannedDeliveryTime" : "", "actualDeliveryDate" : "", "actualDeliveryTime" : "", "deliveredBy" : "", "size1" : 25.0, "size2" : 464.0, "size3" : 46.0, "jobPriority" : 1.0, "cancelReason" : "", "cancelDate" : "", "cancelBy" : "", "reasonCode" : "", "reasonText" : "", "status" : "UNASSIGNED", "lineItems" : [ { "ItemId" : "MMGW001", "size1" : 25.0, "size2" : 464.38, "size3" : 46.875 } ], "locations" : { "lng" : 55.179042, "lat" : 25.098741 } }
MongoDB 3.6及更高版本
作为预览的一部分, $lookup
通过MongoDB 3.6获得了更具performance力的检修。 所以你实际上可以专门说明这些字段返回的方式:
{ "$lookup": { "from": "servicelocations", "let": { "serviceLocationId": "$serviceLocationId" }, "pipeline": [ { "$match": { "$expr": { "$eq": [ "serviceLocationId", "$$serviceLocationId" ] } }}, { "$project": { "_id": 0, "lng": "$location.lng", "lat": "$location.lat" }} ], "as": "locations" }}
实际上发布的时候会更方便些。 这实际上使用$expr
而不是localField
和foreignField
来在子pipe道的$match
阶段中定义“连接”条件。 然后,你可以简单地$project
字段返回,然后进入$lookup
目标数组。
outlook未来,这是你想要采取的一般方法,因为它限制了实际返回的内容。