#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" } }