来自外部集合的项目特定字段$查找结果

我正在写聚合,以获得与本地收集外国收集数据。

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而不是localFieldforeignField来在子pipe道的$match阶段中定义“连接”条件。 然后,你可以简单地$project字段返回,然后进入$lookup目标数组。

outlook未来,这是你想要采取的一般方法,因为它限制了实际返回的内容。