Группа MongoDB для получения минимального значения поля и соответствующих данных - PullRequest
2 голосов
/ 28 апреля 2020

У меня есть коллекция таких продуктов:

[
  {
    productName: "productB",
    productImage: "http://some.url/product_B.jpg",
    productCategoryId: 34,
    productPrice: 10
  },
  {
    productName: "productA",
    productImage: "http://some.url/product_A.jpg",
    productCategoryId: 34,
    productPrice: 50
  }
]

Пока у меня есть следующее:

db.local.aggregate(
   [
      {
         "$match":{
            "productCategoryId":34
         }
      },
      {
         "$facet":{
            "byCategory":[
               {
                  "$group":{
                     "_id":"productCategory",
                     "minprice":{
                        "$min":"$productPrice"
                     }
                  }
               }
            ]
         }
      }
   ]
)

Мне нужно объединить / сгруппировать по одному полю ( Категория) и получить минимальную цену за категорию, но я также хотел бы вернуть название продукта и изображение (другие 2 поля) для документа с минимальной ценой для каждой категории. Кто-нибудь может указать на какое-то направление или примеры? GroupBy и min покрыты, только часть извлечения дополнительной информации. Обновленная схема и агрегация, которые у меня уже есть, @ PulkitAgg1010 Что я хотел бы получить productImage и productPrice для записи с minPrice для каждой категории.

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Вы можете использовать агрегацию ниже

db.collection.aggregate([
  { "$group": {
    "_id": "$productCategory",
    "doc": {
      "$min": {
        "minprice": "$productPrice",
        "productName": "$productName",
        "productCategory": "$productCategory"
      }
    }
  }},
  { "$replaceRoot": { "newRoot": "$doc" }}
])

$min всегда принимает минимальное значение первого выражения, которое передается внутри объекта. Вот это значение.

1 голос
/ 28 апреля 2020

Вам может не понадобиться использовать $facet для этого, попробуйте следующие запросы:

db.collection.aggregate([
    { "$match": { "productCategoryId": 34 } },
    /** group on `productCategoryId` & get `minprice` on all docs & also push all docs into data array, 
     * Also you'll only have `"productCategoryId": 34` so need not to say ``"_id": "$productCategoryId"  in group */
    {
      "$group": { "_id": "$productCategoryId", "minprice": { "$min": "$productPrice" }, data: { $push: "$$ROOT" } }
    },
    /** unwind data array */
    { $unwind: "$data" },
    /** match the docs which have `data.productPrice` equivalent to `minprice` - 
     * If there are multiple matches you can use `$limit` after match stage to limit result */
    {
      $match: {  $expr: { $eq: [ "$data.productPrice", "$minprice" ] } }
    },
    /** make `data` as new root of doc */
    { $replaceRoot: {  newRoot: "$data" } }
  ])

Тест: mongoplayground

Если Вы думаете, что у вас будет слишком много документов, чтобы выполнить $unwind, затем попробуйте выполнить запрос ниже:

db.collection.aggregate([
    { "$match": { "productCategoryId": 34 } },
    /** group on `productCategoryId` & get `minprice` on all docs & also push all docs into data array */
    {
      "$group": { "_id": "$productCategoryId", "minprice": { "$min": "$productPrice" }, data: { $push: "$$ROOT" } }
    },
    /** re-create `data` array with matched docs */
    { $project: { data: { $filter: { input: "$data", cond: { $eq: [  "$$this.productPrice",  "$minprice" ] } } } } },
    /** unwind data array */
    { $unwind: "$data" },
    /** make `data` as new root of doc */
    { $replaceRoot: {  newRoot: "$data" } }
  ])

Тест: mongoplayground

...