Mon go Агрегация БД для сортировки по полю массива, выбора первых трех записей и объединения других записей в одну - PullRequest
1 голос
/ 20 февраля 2020

У меня есть коллекция, в которой есть множество автомобилей, как показано ниже:

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
    }
]

То есть сверху 3 производителя с наибольшим количеством проданных и 4-й записей должны отображаться как «другие» с объединенным значением «numbersSold» для «VW» и «Mercedez Benz», т. Е. 15 + 1

Ответы [ 2 ]

2 голосов
/ 21 февраля 2020

Вы можете достичь этого за 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'] } } }])

Тест: MongoDB-Playground

1 голос
/ 21 февраля 2020

Вы можете использовать структуру агрегации для достижения этого.

Вот запрос:

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
    }
  }
])

После $ sort stage, используйте $ facet , чтобы получить 3 лучших результата с одной стороны, а другие с другой, сгруппировать их и вычислить сумму. Последние этапы после фасета как раз здесь, чтобы отформатировать ваши документы до желаемого результата.

Вы можете проверить это здесь

...