【问题标题】:How to group an array by same value from different collections in Mongo aggregation如何在 Mongo 聚合中按来自不同集合的相同值对数组进行分组
【发布时间】:2021-04-14 19:00:36
【问题描述】:

我需要通过来自engagementsbroadcastreports 的相同coordinates 字段在一个名为location 的数组中进行分组。此外,如果一个coordinate 存在于一个中而另一个上不存在,则无论如何都应该包含它。

在该数组中,我需要包含一个scans,它是与campaign_ad_group 相关的engagements 的数量,以及一个impressions 字段,它是与campaign_ad_group 相关的broadcastreports.analytics.impressions 的总和。

我有以下聚合:

.aggregate([
    {
        $match: {
            '_id': ObjectId("60520e1d09ba3a769ab85f68"),
            }
        },
          {
                $project: {
                    '_id': 1,
                    'broadcasts_to': 1
                    }
                },
        {
       $lookup: {
           from: 'campaignadgroups',
           localField: '_id',
           foreignField: 'campaign_id',
           as:'campaign_ad_group'
           }   
       },
       {
           $unwind: '$campaign_ad_group'
        },
          {
                $lookup: {
                    from: 'broadcastplans',
                    let: { 'campaign_ad_group_id': '$campaign_ad_group._id' },
                    as: 'broadcastplans',
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $eq: ['$campaign_ad_group_id','$$campaign_ad_group_id' ]
                                    }
                                } 
                            },
                            { $project: { '_id': 1 } }         
                    ]
                    }
                },
         // Above it's only the necessary data gathering to get the needed engagements and broadcastreports.


                 {
                    $lookup: {
                        from: 'engagements',
                        let: { 'broadcastplan_ids': '$broadcastplans._id' },
                        as: 'engagements',
                        pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                    { $in: ['$broadcast_plan_id', '$$broadcastplan_ids'] },
                                    { $gte: ['$reported_at', ISODate('2019-12-29T15:02:47.305Z')] },
                                    { $lte: ['$reported_at', ISODate('2021-12-29T15:02:47.305Z')] }
                                    ]
                                    }
                                }
                            }
                        ]
                        }
                    },
                    {
                        $unwind: '$engagements'
                        },
                 
                 {
                     $group: {
                         '_id': {
                             'adgroup_id': '$campaign_ad_group._id',
                             'coordinates': '$engagements.location.coordinates',
                             },
                             'adgroup_name': {$first: '$campaign_ad_group.name'},
                             'scans': {$sum: 1}
                         }
                     },
                     {
                         $group: {
                             '_id': '$_id.adgroup_id',
                             'name': {$first: '$adgroup_name'},
                             'location': {
                                 $push: {
                                     'scans': '$scans',
                                     'coordinates': '$_id.coordinates'
                                     }
                                 }
                             }
                         }
])

我得到的输出如下:

{
    "_id" : ObjectId("5fe9f89f603eaa22b3d374f5"),
    "name" : "Sick name",
    "location" : [ 
        {
            "scans" : 1.0,
            "coordinates" : [ 
                -8.63294964028813, 
                56.1520268933931
            ]
        }, 
        {
            "scans" : 1.0,
            "coordinates" : [ 
                -9.63294964028813, 
                58.1520268933931
            ]
        }
    ]
}

现在是我卡在的部分。我需要查找集合broadcastreports 并按其坐标与engagements 坐标进行分组,并包含一个字段impressions,它是broadcastreports.analytics.impressions 的总和。

通过删除group 管道并从broadcastreports 中查找,它将如下所示:

.aggregate([
  .
  . // ABOVE IS THE SAME DATA GATHERING AS BEFORE
  .
                 {
                    $lookup: {
                        from: 'engagements',
                        let: { 'broadcastplan_ids': '$broadcastplans._id' },
                        as: 'engagements',
                        pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                    { $in: ['$broadcast_plan_id', '$$broadcastplan_ids'] },
                                    { $gte: ['$reported_at', ISODate('2019-12-29T15:02:47.305Z')] },
                                    { $lte: ['$reported_at', ISODate('2021-12-29T15:02:47.305Z')] }
                                    ]
                                    }
                                }
                            }
                        ]
                        }
                    },
                      
  
                      {
                        $lookup: {
                            from: 'broadcastreports',
                            let: { 'broadcastplan_ids': '$broadcastplans._id' },
                            as: 'broadcastreports',
                            pipeline: [
                                {
                                    $match: {
                                        $expr: {
                                             $and: [
                                    { $in: ['$broadcast_plan_id', '$$broadcastplan_ids'] },
                                    { $gte: ['$reported_at', ISODate('2019-12-29T15:02:47.305Z')] },
                                    { $lte: ['$reported_at', ISODate('2021-12-29T15:02:47.305Z')] }
                                    ]
                                            }
                                        }
                                    }
                            ]
                            }
                        },
                    
])

这让我得到了我需要的所有数据,例如:

{
 _id: ObjectId("60520e1d09ba3a769ab85f68"),

 campaign_ad_group: {
                _id: ObjectId("5fc1215a039674c600c0f533"),
                name: 'Sick name'
               },

 broadcastplans: [_ids],

 engagements: [ 
   {
    _id,
    coordinates: [-9.63294964028813,58.1520268933931],
    reported_at: Date
   },
   {
   _id,
   coordinates: [-8.63294964028813,56.1520268933931],
   reported_at: Date
   }
 ],

broadcastreports: [
  {
    _id,
    coordinates: [-9.63294964028813,58.1520268933931],
    reported_at: Date,
    analytics: {
      impressions: 10
    }
  },
  {
   _id,
    coordinates: [-5.20923334343244,40.4874833434234],
    reported_at: Date,
    analytics: {
      impressions: 5
    }
  }
]
}

我需要以一种我得到以下输出的方式对它进行分组:

[
 {
  _id: campaign_ad_group._id,
  name: campaign_ad_group.name,
  location: [
   {
    scans: 1,
    impressions: 10,
    coordinates: [-9.63294964028813,58.1520268933931]
   },
  {
    scans: 0, // This coordinate does not exist on the engagements so its 0 but needs to be 
              // included anyway.
    impressions: 5,
    coordinates: [-5.20923334343244,40.4874833434234]
    },
   {
    scans: 1,
    impressions: 0, // Same here
    coordinates: [-8.63294964028813,56.1520268933931]
   },
  ]
 }
]

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    【讨论】:

    • 谢谢。能够通过unionWith 做到这一点,我将发布我是如何做到的,以便帮助其他人。
    【解决方案2】:

    解决方案是使用 unionWith。我是这样做的:

    .aggregate([
        {
            $match: {
                '_id': ObjectId("60520e1d09ba3a769ab85f68"),
                }
            },
              {
                    $project: {
                        '_id': 1,
                        'broadcasts_to': 1
                        }
                    },
            {
           $lookup: {
               from: 'campaignadgroups',
               localField: '_id',
               foreignField: 'campaign_id',
               as:'campaign_ad_group'
               }   
           },
           {
               $unwind: '$campaign_ad_group'
            },
              {
                    $lookup: {
                        from: 'broadcastplans',
                        let: { 'campaign_ad_group_id': '$campaign_ad_group._id' },
                        as: 'broadcastplans',
                        pipeline: [
                            {
                                $match: {
                                    $expr: {
                                        $eq: ['$campaign_ad_group_id','$$campaign_ad_group_id' ]
                                        }
                                    } 
                                },
                                { $project: { '_id': 1 } }         
                        ]
                        }
                    },
    // Needed data gathering for the next lookups
    
                     {
                        $lookup: {
                            from: 'engagements',
                            let: { 'broadcastplan_ids': '$broadcastplans._id' },
                            as: 'locations',
                            pipeline: [
                            {
                                $match: {
                                    $expr: {
                                        $and: [
                                        { $in: ['$broadcast_plan_id', '$$broadcastplan_ids'] },
                                        { $gte: ['$reported_at', ISODate('2019-12-29T15:02:47.305Z')] },
                                        { $lte: ['$reported_at', ISODate('2021-12-29T15:02:47.305Z')] }
                                        ]
                                        }
                                    }
                                },
                                {
                                    $group: {
                                        '_id': '$location.coordinates',
                                        'location': {$first:'$location'},
                                        'scans': {$sum: 1}
                                        }
                                    },
                                {
                                    $unionWith: {
                                        coll: 'broadcastreports',
                                        pipeline: [
                                            {
                                                $match: {
                                                    $expr: {
                                                        $and: [
                                                            { $in: ['$broadcast_plan_id', '$$broadcastplan_ids'] },
                                                            { $gte: ['$reported_at', ISODate('2019-12-29T15:02:47.305Z')] },
                                                            { $lte: ['$reported_at', ISODate('2021-12-29T15:02:47.305Z')] }
                                                          ]
                                                    }
                                                }
                                            },
                                        ]
                                        }
                                    },
                                    
                                    {
                                        $group: {
                                            '_id': '$location.coordinates',
                                            'impressions': {$sum: '$analytics.impressions'},
                                            'scans': {$first: '$scans'}
                                            }
                                        },
                                        {
                                            $project: {
                                                '_id': 0,
                                                'coordinates': '$_id',
                                                'impressions': {$ifNull: ['$impressions', 0]},
                                                'scans': {$ifNull: ['$scans',0]}
                                                }
                                            }
                            ]
                            }
                        },
                        
                        {
                            $group: {
                                '_id': '$campaign_ad_group._id',
                                'name': {$first:'$campaign_ad_group.name'},
                                'locations': {$first: '$locations'}
                                
                                }
                            }
    
    ])
    

    输出:

    {
        "_id" : ObjectId("5fe9f89f603eaa22b3d374f5"),
        "name" : "Sick name",
        "locations" : [ 
            {
                "coordinates" : [ 
                    -9.63294964028813, 
                    42.1520268933931
                ],
                "impressions" : 0,
                "scans" : 1.0
            }, 
            {
                "coordinates" : [ 
                    -8.63294964028813, 
                    41.1520268933931
                ],
                "impressions" : 0,
                "scans" : 1.0
            }, 
            {
                "coordinates" : [ 
                    0, 
                    0
                ],
                "impressions" : 1,
                "scans" : 0.0
            }
        ]
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-10
      • 2021-09-17
      • 1970-01-01
      • 2023-01-20
      • 1970-01-01
      • 2016-03-20
      • 2023-03-23
      • 2021-01-31
      相关资源
      最近更新 更多