【问题标题】:Mongodb aggregation group by inner arrayMongodb聚合组按内部数组
【发布时间】:2021-03-02 19:48:31
【问题描述】:

我已汇总我的数据以提供此输出。

[
  {
    "_id": {
      "source": "source_1",
      "medium": "medium_1",
      "campaign": "campaign_1"
    },
    "visitors": [
      {
        "_id": "60073f564d6c915237dbe158",
        "location": {
          "city": "Miami",
          "postal": "33177"
        }
      },
      {
        "_id": "60073f564d6c915237dbe158",
        "location": {
          "city": "Miami",
          "postal": "33163"
        }
      }
    ]
  },
  {
    "_id": {
      "source": "source_2",
      "medium": "medium_2",
      "campaign": "campaign_2"
    },
    "visitors": [
      {
        "_id": "60073f564d6c915237dbe158",
        "location": {
          "city": "Miami",
          "postal": "33177"
        }
      },
      {
        "_id": "60073f564d6c915237dbe158",
        "location": {
          "city": "Miami",
          "postal": "33162"
        }
      }
    ]
  }
]

我想对内部访问者数组进行分组并获得此输出。

[
  {
    "_id": {
      "source": "source_1",
      "medium": "medium_1",
      "campaign": "campaign_1"
    },
    "visitors": [
      {
        "city": "Miami",
        "postal": "33177",
        "count": 2
      },
      {
        "city": "Miami",
        "postal": "33163",
        "count": 5
      }
    ]
  },
  {
    "_id": {
      "source": "source_2",
      "medium": "medium_2",
      "campaign": "campaign_2"
    },
    "visitors": [
      {
        "city": "Miami",
        "postal": "33177",
        "count": 1
      },
      {
        "city": "Miami",
        "postal": "33163",
        "count": 3
      }
    ]
  }
]

在活动集合上执行的聚合管道:

[{$match: {
  website_id: 1,
  $or: [
    {
      source:{
        $regex:/goo/,
        $options: 'i'
      }
    },
    {
      medium:{
        $regex:/goo/,
        $options: 'i'
      }
    },
    {
      campaign:{
        $regex:/goo/,
        $options: 'i'
      }
    }
  ]
}}, {$addFields: {
  visitor_id: {
    $toObjectId: "$visitor_id"
  }
}}, {$lookup: {
  from: 'visitors',
  localField: 'visitor_id',
  foreignField: '_id',
  as: 'visitors'
}}, {$unwind: {
  path: '$visitors'
}}, {$group: {
  _id: {
    source: '$source',
    medium: '$medium',
    campaign: '$campaign',
  },
  visitors:{
    $push: '$visitors'
  }
}}, {$unwind: {
  path: '$visitors'
}}, {$group: {
  _id: {
    'city': '$visitors.location.city',
    'postal': '$visitors.location.postal'
  },
  'count': {
    '$sum': 1
  }
}}, {$project: {
  '_id': 0,
  'city': '$_id.city',
  'postal': '$_id.postal',
  'count': '$count',
  'total': {
    '$sum': '$count'
  }
}}, {$project: {
  'city': '$city',
  'postal': '$postal',
  'count': '$count',
  'total': {
    '$sum': '$total'
  }
}}]

【问题讨论】:

  • 您可以发布示例文档吗?以及您尝试过的查询。
  • @turivishal 用使用的文档和管道更新了问题。

标签: mongodb aggregation-framework


【解决方案1】:

因此,我们的想法是首先按访问者的postal 号码以及活动详细信息对访问者进行分组以获取计数,然后仅按活动详细信息进行汇总以累积访问者。 试试这个查询:

db.campaigns.aggregate([
    {
        $match: {
            // Put your condtions here.
        }
    },
    {
        $project: {
            source: 1,
            medium: 1,
            campaign: 1,
            visitor_id: 1
        }
    },
    {
        $addFields: {
            visitor_id: { $toObjectId: "$visitor_id" }
        }
    },
    {
        $lookup: {
            from: "visitors",
            let: { "visitor_id": "$visitor_id" },
            pipeline: [
                {
                    $match: {
                        $expr: { $eq: ["$_id", "$$visitor_id"] }
                    }
                },
                {
                    $project: {
                        location: {
                            city: 1,
                            postal: 1
                        }
                    }
                }
            ],
            as: "visitor"
        }
    },
    { $unwind: "$visitor" },
    {
        $group: {
            _id: {
                source: "$source",
                medium: "$medium",
                campaign: "$campaign",
                postal: "$visitor.location.postal"
            },
            visitors: { $push: "$visitor" },
            count: { $sum: 1 }
        }
    },
    {
        $group: {
            _id: {
                source: "$_id.source",
                medium: "$_id.medium",
                campaign: "$_id.campaign"
            },
            visitors: {
                $push: {
                    city: { $arrayElemAt: ["$visitors.location.city", 0] },
                    postal: { $arrayElemAt: ["$visitors.location.postal", 0] },
                    count: "$count"
                }
            }
        }
    }
]);

【讨论】:

    【解决方案2】:

    你需要纠正小组赛阶段,

    • $group by source, medium, campaignpostal, 得到第一个 city 并计算总和
    • $group by source, medium, campaign 并使用必填字段构造访问者数组
    db.campaigns.aggregate([
      { $match: .. } //skipped
      { $addFields: .. }, //skipped
      { $lookup: .. }, //skipped
      { $unwind: .. }, //skipped
      {
        $group: {
          _id: {
            source: "$source",
            medium: "$medium",
            campaign: "$campaign",
            postal: "$visitors.location.postal"
          },
          city: { $first: "$visitors.location.city" },
          count: { $sum: 1 }
        }
      },
      {
        $group: {
          _id: {
            source: "$_id.source",
            medium: "$_id.medium",
            campaign: "$_id.campaign"
          },
          visitors: {
            $push: {
              city: "$city",
              postal: "$_id.postal",
              count: "$count"
            }
          }
        }
      }
    ])
    

    Playground

    【讨论】:

      猜你喜欢
      • 2019-05-17
      • 2020-09-05
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多