Mongodb Mongo DB aggregation按数组字段排序,选择前三条记录并将其他记录合并为一条

Mongodb Mongo DB aggregation按数组字段排序,选择前三条记录并将其他记录合并为一条,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我收集了一系列汽车,如下所示: cars:[ { "manufacturer": "Skoda", "numbersSold": 40 }, { "manufacturer": "Hyundai", "numbersSold": 90 }, { "manufacturer": "Maruti", "numbersSold": 400 }, {

我收集了一系列汽车,如下所示:

cars:[
    {
        "manufacturer": "Skoda",
        "numbersSold": 40
    },
    {
        "manufacturer": "Hyundai",
        "numbersSold": 90
    },
    {
        "manufacturer": "Maruti",
        "numbersSold": 400
    },
    {
        "manufacturer": "VW",
        "numbersSold": 15
    },
    {
        "manufacturer": "Mercedez Benz",
        "numbersSold": 1
    }
]
是否可以在此集合上运行聚合以生成以下结果:

cars:[
    {
        "manufacturer": "Maruti",
        "numbersSold": 400
    },
    {
        "manufacturer": "Hyundai",
        "numbersSold": 90
    },
    {
        "manufacturer": "Skoda",
        "numbersSold": 40
    },
    {
        "manufacturer": "Other",
        "numbersSold": 16
    }
]
也就是说,销量最多的前三大制造商和第四大记录应显示为大众和Mercedez-Benz的销量组合值,即15+1,您可以用来实现这一点

问题是:

db.collection.aggregate([
  {
    $sort: {
      "numbersSold": -1
    }
  },
  {
    $facet: {
      bestThree: [
        {
          $limit: 3
        }
      ],
      others: [
        {
          $skip: 3
        },
        {
          $addFields: {
            manufacturer: "others"
          }
        },
        {
          $group: {
            _id: null,
            manufacturer: {
              $first: "$manufacturer"
            },
            numbersSold: {
              $sum: "$numbersSold"
            }
          }
        }
      ]
    }
  },
  {
    $project: {
      result: {
        $concatArrays: [
          "$bestThree",
          "$others"
        ]
      }
    }
  },
  {
    $unwind: "$result"
  },
  {
    $replaceRoot: {
      newRoot: "$result"
    }
  },
  {
    $project: {
      _id: 0
    }
  }
])
在阶段结束后,一方面使用获得你的3个最佳结果,另一方面使用其他结果,将这些结果分组并计算总和。 facet之后的最后阶段就是将文档格式化为所需的输出

您可以测试它

您可以使用它来实现这一点

问题是:

db.collection.aggregate([
  {
    $sort: {
      "numbersSold": -1
    }
  },
  {
    $facet: {
      bestThree: [
        {
          $limit: 3
        }
      ],
      others: [
        {
          $skip: 3
        },
        {
          $addFields: {
            manufacturer: "others"
          }
        },
        {
          $group: {
            _id: null,
            manufacturer: {
              $first: "$manufacturer"
            },
            numbersSold: {
              $sum: "$numbersSold"
            }
          }
        }
      ]
    }
  },
  {
    $project: {
      result: {
        $concatArrays: [
          "$bestThree",
          "$others"
        ]
      }
    }
  },
  {
    $unwind: "$result"
  },
  {
    $replaceRoot: {
      newRoot: "$result"
    }
  },
  {
    $project: {
      _id: 0
    }
  }
])
在阶段结束后,一方面使用获得你的3个最佳结果,另一方面使用其他结果,将这些结果分组并计算总和。 facet之后的最后阶段就是将文档格式化为所需的输出


您可以测试它

您可以通过以下查询在5个步骤/阶段中实现:

db.cars.aggregate([

    /** Remove _id field in cars collection, which also reduces size of doc a bit by removing a field across all docs */
    { $project: { _id: 0 } },

    /** Sort to get top manufacturers */
    { $sort: { numbersSold: -1 } },

    /** group to push all manufacturers into an array */
    { $group: { _id: '', cars: { $push: '$$ROOT' } } },

    /** project to seperate top 3 manufacturers & others */
    {
        $project: {
            _id: 0, others: [{
                $reduce: {
                    input: { $slice: ["$cars", 3, { $size: '$cars' }] },
                    initialValue: { numbersSold: 0 },
                    in: { "manufacturer": 'Other', numbersSold: { $add: ["$$value.numbersSold", "$$this.numbersSold"] } }
                }
            }], cars: { $slice: ["$cars", 3] }
        }
    },

    /** project to merge top 3 manufacturers & others into one array named cars */
    { $project: { cars: { $concatArrays: ['$cars', '$others'] } } }])

测试:

您可以使用以下查询在5个步骤/阶段中实现这一点:

db.cars.aggregate([

    /** Remove _id field in cars collection, which also reduces size of doc a bit by removing a field across all docs */
    { $project: { _id: 0 } },

    /** Sort to get top manufacturers */
    { $sort: { numbersSold: -1 } },

    /** group to push all manufacturers into an array */
    { $group: { _id: '', cars: { $push: '$$ROOT' } } },

    /** project to seperate top 3 manufacturers & others */
    {
        $project: {
            _id: 0, others: [{
                $reduce: {
                    input: { $slice: ["$cars", 3, { $size: '$cars' }] },
                    initialValue: { numbersSold: 0 },
                    in: { "manufacturer": 'Other', numbersSold: { $add: ["$$value.numbersSold", "$$this.numbersSold"] } }
                }
            }], cars: { $slice: ["$cars", 3] }
        }
    },

    /** project to merge top 3 manufacturers & others into one array named cars */
    { $project: { cars: { $concatArrays: ['$cars', '$others'] } } }])
测试: