MongoDB ограничивает группу по результатам

#mongodb #aggregation-framework #mongoengine

#mongodb #структура агрегации #mongoengine

Вопрос:

В моей базе данных mongo есть документ со следующей структурой:

 {'vname':'x', 'pname': 'xyz', 'price': '10000'}
  

Я хочу получить все документы, которые соответствуют pname='xy' , а затем сгруппировать vname и ограничить результаты для каждого vname на 4.

 pipeline = [
    {
        '$facet': {
            'v1': [
                {
                    '$match': {'vname': 'v1'}
                },
                {
                    '$sort': {'price': 1}
                },
                {
                    '$limit': 4
                }
            ],
            'v2': [
                {
                    '$match': {'vname': 'v2'}
                },
                {
                    '$sort': {'price': 1}
                },
                {
                    '$limit': 4
                }
            ]
        }
    }
]

docs = Pinfo.objects(pname__icontains='xy').aggregate(pipeline=pipeline)
  

Другой способ, который я вижу, — запустить запрос фильтра несколько раз для каждого vname

 docs = Pinfo.objects.filter(Q(pname__icontains='xy')amp;Q(vname__exact='v1')).limit(4)
  

Любой другой способ добиться того же?
Является ли использование агрегированного и конвейерного подхода лучшим способом?

Ответ №1:

Вы можете попробовать,

  • $match pname условие
  • $sort в pname порядке возрастания (необязательно)
  • $group vname и помещает корневой объект в элементы и создает массив
  • $project чтобы отобразить обязательные поля и получить 4 объекта, используя $slice
 db.collection.aggregate([
  { $match: { pname: "xy" } },
  { $sort: { pname: 1 } },
  {
    $group: {
      _id: "$vname",
      items: { $push: "$$ROOT" }
    }
  },
  {
    $project: {
      _id: 0,
      vname: "$_id",
      items: { $slice: ["$items", 4] }
    }
  }
])
  

Игровая площадка


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

  • $unwind деконструировать массив элементов в объект
  • $replaceRoot для замены объекта items в корне
   { $unwind: "$items" },
  { $replaceRoot: { newRoot: "$items" } }
  

Игровая площадка