MongoDB: выберите первые N записей на основе предложения group by - PullRequest
2 голосов
/ 26 мая 2020

Ниже мой образец коллекции: -

{
"_id" : "fffdb22b-912d-4166-909b-7d0fe790ba2a", 
"companyVendorId" : "1001", 
"date" : ISODate("2019-01-02T05:30:00.000+05:30"),  
"amount" : 100  
},
{
"_id" : "fff94874-27af-4a39-ae59-3a46b8c7f573", 
"companyVendorId" : "1002", 
"date" : ISODate("2019-01-25T05:30:00.000+05:30"),  
"amount" : 200  
 },
{
"_id" : "fff94874-27af-4a39-ae59-3a46b8c7f573", 
"companyVendorId" : "1002", 
"date" : ISODate("2019-01-29T05:30:00.000+05:30"),  
"amount" : 200  
 },

{
"_id" : "fff68faf-2f11-480f-83d2-bfcb45b12d5b", 
"companyVendorId" : "1004", 
"date" : ISODate("2019-01-12T05:30:00.000+05:30"),  
"amount" : 500

 },

{
"_id" : "fff4dfaa-46cd-48e3-a871-1f086a2c5438", 
"companyVendorId" : "1005", 
"date" : ISODate("2019-02-13T05:30:00.000+05:30"),  
"amount" :600

 },

 {
"_id" : "fff18ff2-015e-4ddc-81f2-a12ab3503d05", 
"companyVendorId" : "1006", 
"date" : ISODate("2019-02-08T05:30:00.000+05:30"),  
"amount" : 700

},
{
"_id" : "ffeb16cd-ae1b-4c1e-aa93-d64347b5ff38", 
"companyVendorId" : "1007", 
"date" : ISODate("2019-02-18T05:30:00.000+05:30"),  
"amount" :800
}

Требование : - Мне нужны 2 ведущих поставщика за каждый месяц (за текущий год) в зависимости от их количества, если их больше одного транзакции существуют для одного и того же "companyVendorId" в течение одного месяца, тогда нам нужно показать сумму суммы.

Ожидаемый результат : -

{
"month":1
"companyVendorId" : "1004",     
"totalAmount" : 500 
 },
{
 "month":1
"companyVendorId" : "1002",     
"totalAmount" : 400

 },
{
"month":2
"companyVendorId" : "1007",         
"totalAmount" :800
 },

{
"month":2   
"companyVendorId" : "1006",     
"totalAmount" : 700

}

Пока я нахожусь в между попытками сделать запрос, под запросом, который я могу сделать: -

 db.getCollection('transaction').aggregate([
 {
"$project":
 {
 "amount": 1,
 "companyVendorId":1,

 "month": { "$month": "$date" }, "year": { "$year": "$date" }

 }
 },
 {
 "$match":
   {
    "year": 2020
   }

  }, {
 "$group": {
    "_id": {
    "month": "$month",
   "companyVendorId":"$companyVendorId"
    },
   "totalAmount": { "$sum": "$amount" }
     }
     }
    ])

Этот запрос дает мне результат на основе моих требований, но не может выбрать 2 лучших поставщика.

1 Ответ

0 голосов
/ 27 мая 2020

Немного complicated. Этапы 7 и 8 являются наиболее сложной частью, так как вам нужно суммировать поставщиков с одинаковым идентификатором. Если топовые 2...n поставщики совпадают, нам нужно суммировать их всех и считать это поставщиком Nº1. Тот же процесс для поставщика Nº2.

Объяснение

  1. Этап 1. Если вы хотите применить индексы MongoDB, мы можем фильтровать записи по полю date. Если нет индексов, вы можете заменить свои 2 этапа на мои.
  2. Этап 2. Мы группируем по month и создаем два массива со значениями companyVendorId и amount.
  3. Этапы 3-4. Мы сглаживаем массив data2 для вычисления $max / $min сумм на companyVendorId. Это поможет нам суммировать ведущих поставщиков с одинаковыми companyVendorId.
  4. этапами 5-6. Теперь мы заказываем поставщиков с наивысшим amount и определяем список уникальных продавцов с суммами $max / $min.
  5. Этап 7. Здесь мы фиксируем количество поставщиков min. Поскольку $group принимает наименьшее значение, мы заменяем его следующим значением max поставщика: {companyVendorId:1, max:500, min:50}, ---\ {companyVendorId:1, max:500, min:200}, {companyVendorId:2, max:400, min:200} ---/ {companyVendorId:2, max:400, min:200}

  6. Этап 8. Теперь мы суммируем поставщиков с одинаковыми companyVendorId и amount между значениями min и max.

  7. 9-10-11 этапы. Мы сглаживаем предыдущий результат, преобразуем его в желаемый и сортируем документы.

db.transaction.aggregate([
  {
    "$match": {
      "date": {
        "$gte": ISODate("2019-01-01T00:00:00Z"),
        "$lte": ISODate("2019-12-31T23:59:59Z")
      }
    }
  },
  {
    "$group": {
      "_id": {
        "$month": "$date"
      },
      "data": {
        "$push": {
          "_id": {
            "$month": "$date"
          },
          "companyVendorId": "$companyVendorId",
          "amount": "$amount"
        }
      },
      "data2": {
        "$push": {
          "companyVendorId": "$companyVendorId",
          "amount": "$amount"
        }
      }
    }
  },
  {
    "$unwind": "$data2"
  },
  {
    "$group": {
      "_id": {
        "month": "$_id",
        "companyVendorId": "$data2.companyVendorId"
      },
      "data": {
        "$first": "$data"
      },
      "max": {
        "$max": "$data2.amount"
      },
      "min": {
        "$min": "$data2.amount"
      }
    }
  },
  {
    "$sort": {
      "_id.month": 1,
      "max": -1
    }
  },
  {
    "$group": {
      "_id": "$_id.month",
      "data": {
        "$first": "$data"
      },
      "data2": {
        "$push": {
          "companyVendorId": "$_id.companyVendorId",
          "max": "$max",
          "min": "$min"
        }
      }
    }
  },
  {
    $addFields: {
      data2: {
        $map: {
          input: {
            $range: [
              0,
              {
                $min: [
                  {
                    $size: "$data2"
                  },
                  2
                ]
              },
              1
            ]
          },
          as: "i",
          in: {
            companyVendorId: {
              $arrayElemAt: [
                "$data2.companyVendorId",
                "$$i"
              ]
            },
            max: {
              $arrayElemAt: [
                "$data2.max",
                "$$i"
              ]
            },
            min: {
              $ifNull: [
                {
                  $arrayElemAt: [
                    "$data2.max",
                    {
                      $add: [
                        "$$i",
                        1
                      ]
                    }
                  ]
                },
                {
                  $arrayElemAt: [
                    "$data2.min",
                    "$$i"
                  ]
                }
              ]
            }
          }
        }
      }
    }
  },
  {
    $addFields: {
      data3: {
        $map: {
          input: {
            $slice: [
              "$data2",
              2
            ]
          },
          as: "topN",
          in: {
            $reduce: {
              input: "$data",
              initialValue: {
                _id: "",
                companyVendorId: "$$topN.companyVendorId",
                amount: 0
              },
              in: {
                _id: "$_id",
                companyVendorId: "$$value.companyVendorId",
                amount: {
                  $add: [
                    "$$value.amount",
                    {
                      $cond: [
                        {
                          $and: [
                            {
                              $eq: [
                                "$$value.companyVendorId",
                                "$$this.companyVendorId"
                              ]
                            },
                            {
                              $gte: [
                                "$$this.amount",
                                "$$topN.min"
                              ]
                            },
                            {
                              $lte: [
                                "$$this.amount",
                                "$$topN.max"
                              ]
                            }
                          ]
                        },
                        "$$this.amount",
                        0
                      ]
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  {
    $unwind: "$data3"
  },
  {
    $replaceWith: "$data3"
  },
  {
    $sort: {
      _id: 1,
      amount: -1
    }
  }
])

MongoPlayground

Примечание: Вы нужен MongoDB v4.2. Для более ранних версий (>v3.4) замените:

{ $replaceWith: "$data3" }
         with 
{ $replaceRoot: {newRoot: "$data3" }}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...