mongoDB对嵌套对象数组的聚合查找

Posted

技术标签:

【中文标题】mongoDB对嵌套对象数组的聚合查找【英文标题】:mongoDB aggregate lookup on nested array of objects 【发布时间】:2020-01-24 17:13:14 【问题描述】:

我有一个如下所示的集合,但我无法执行 $lookup 并以最初的方式返回它,但填充字段:

我已经在我想要填充的字段上创建了 cmets(代理、missions.clients.client)

   
   "title":"Tournée libre",
   "agent":"5d811943d2a2100017667228", // needs to be populated
   "missions":[  
        
         "_id":"5d8a075346f10d679ab4383e",
         "title":"Journée 3",
         "clients":[  
              
               "_id":"5d8a075346f10d679ab4383f",
               "valid":true,
               "client":"5d1bc39aa2af623b94363b33", // this needs to be populated
               "visit_time":"2019-09-24T12:03:38.383Z"
            ,
              

               "_id":"5d8a0dc446f10d679ab43888",
               "valid":true,
               "client":"5d8a0c8346f10d679ab43886",
               "visit_time":"2019-09-24T12:34:23.210Z"
            ,

         ]
      
   ],
   "created_at":"2019-09-24T12:08:51.928Z",
   "__v":2

结果应该是这样的:

   
   "title":"Tournée libre",
   "agent": firstname: 'something', lastname: 'something else'
   "missions":[  
        
         "_id":"5d8a075346f10d679ab4383e",
         "title":"Journée 3",
         "clients":[  
              
               "_id":"5d8a075346f10d679ab4383f",
               "valid":true,
               "client": firstname: 'something', lastname: 'something else',
               "visit_time":"2019-09-24T12:03:38.383Z"
            ,
              

               "_id":"5d8a0dc446f10d679ab43888",
               "valid":true,
               "client":firstname: 'something', lastname: 'something else',
               "visit_time":"2019-09-24T12:34:23.210Z"
            ,

         ]
      
   ],
   "created_at":"2019-09-24T12:08:51.928Z",
   "__v":2

【问题讨论】:

.populate(agentmissions.clients.client') 试试看 我正在使用填充,但考虑到我正在实现分页并且我有用户角色,我遇到了性能问题。所以我要的是聚合 【参考方案1】:

您可以使用以下聚合管道。

$lookup 填充代理,然后 $reduce 和 $concatArrays 收集所有客户端 ID,$lookup 获取客户端详细信息。

$addFields 和 $map 来迭代任务数组,并为每个客户端通过客户端 ID 和 $mergeObjects 查找来映射前一阶段的客户端信息以保留其他字段。 $project 阶段删除多余的字段。

Mongo db 3.6 及更高版本

Model.aggregate([
 "$lookup":
  "from":"agents",
  "localField":"agent",
  "foreignField":"_id",
  "as":"agent"
 ,
 "$addFields":"agent":"$arrayElemAt":["$agent",0],
 "$addFields":
   "client_ids":
     "$reduce":
       "input":"$missions",
       "initialValue":[],
       "in": "$concatArrays":["$$value","$$this.clients.client"]
     
   
 ,
 "$lookup":
   "from":"clients",
   "localField":"client_ids",
   "foreignField":"_id",
   "as":"client_info"
 ,
 "$addFields":
   "missions":
     "$map":
       "input":"$missions",
       "in":
         "$mergeObjects":[
           "$$this",
           "clients":"$map":
             "input":"$$this.clients",
             "in":"$mergeObjects":[
               "$$this",
              "client":"$arrayElemAt":[
                "$client_info",
                "$indexOfArray":["$client_ids","$$this._id"]
              ]
            ]
           
         ]
       
     
   
 ,
 "$project":"client_ids":0,"client_info":0
])

Mongo db 小于 3.6

$lookup 填充代理,然后 $unwind 到达客户端并查找以获取客户端详细信息。使用 $group 倒带以恢复具有填充值的原始结构。

Model.aggregate([
 "$lookup":
  "from":"agents",
  "localField":"agent",
  "foreignField":"_id",
  "as":"agent"
 ,
 "$addFields":"agent":"$arrayElemAt":["$agent",0],
 "$unwind":"$missions",
 "$unwind":"$missions.clients",
 "$lookup":
   "from":"clients",
   "localField":"missions.clients.client",
   "foreignField":"_id",
   "as":"missions.clients.client"
 ,
 "$addFields":"missions.clients.client":"$arrayElemAt":["$missions.clients.client",0],
 "$group":
   "_id":"_id":"$_id","mission_id":"$missions._id",
   "agent":"$first":"$agent",
   "title":"$first":"$missions.title",
   "clients":"$push":"$missions.clients"
 ,
 "$group":
   "_id":"$_id._id",
   "agent":"$first":"$agent",
   "missions":
     "$push":
       "_id":"$_id.mission_id",
       "title":"$title",
       "clients":"$clients"
      
    
 
])

【讨论】:

以上是关于mongoDB对嵌套对象数组的聚合查找的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB:如何使用查找查询填充嵌套对象?

如何在 mongodb 聚合中展开嵌套对象数组?

具有嵌套对象数组的 MongoDB 聚合

MongoDB 聚合与嵌套的对象属性数组与日期

使用聚合和查找 mongodb 从对象数组中获取最小值

使用聚合和查找 mongodb 从对象数组中获取最小值