Первые два шага достаточно просты:
X = 1; Y = 3
db.collection.aggregate( [
{ $match: { Group: { $gte: X, $lt: Y } } },
{ $group: { _id: '$Group' } }
] );
С приведенным выше набором данных это дает вам:
{ "result" : [ { "_id" : 2 }, { "_id" : 1 } ], "ok" : 1 }
Чтобы иметь возможность выбрать K документов с наибольшим значением, вам нужно изменить свою группу, включив в нее каждый документ и максимальное значение для этой группы, а затем раскрутить, чтобы мы могли сортировать по группе и значению (DESC):
db.collection.aggregate( [
{ $match: { Group: { $gte: X, $lt: Y } } },
{ $group: {
_id: '$Group',
docs: { $push: { _id: '$_id', Group: '$Group', Value: '$Value' } }
} },
{ $unwind: '$docs' },
{ $sort: { 'docs.Group': 1, 'docs.Value': -1 } }
] );
Однако с этого момента мы поражены тем, что в отличие от $push в качестве обычного оператора запроса, мы пока не можем выполнить $push + $slice в структуре агрегации. Единственное, что мы можем сделать, это еще одна группа, чтобы ваше приложение могло выбрать K документов в группе с наивысшими значениями:
db.collection.aggregate( [
{ $match: { Group: { $gte: X, $lt: Y } } },
{ $group: {
_id: '$Group',
docs: { $push: { _id: '$_id', Group: '$Group', Value: '$Value' } }
} },
{ $unwind: '$docs' },
{ $sort: { 'docs.Group': 1, 'docs.Value': -1 } }
{ $group: {
_id: '$docs.Group',
docs: { $push: {
_id: '$docs._id',
Group: '$docs.Group',
Value: '$docs.Value'
} }
} }
] );
Что затем выводит (после добавления еще нескольких документов):
{
"result" : [
{
"_id" : 2,
"docs" : [
{
"_id" : ObjectId("51e3a73dea832e98dd545f68"),
"Group" : 2,
"Value" : 22
},
{
"_id" : ObjectId("51e3a738ea832e98dd545f66"),
"Group" : 2,
"Value" : 17
},
{
"_id" : ObjectId("51e3a73aea832e98dd545f67"),
"Group" : 2,
"Value" : 13
},
{
"_id" : ObjectId("51e3a2aaea832e98dd545f64"),
"Group" : 2,
"Value" : 8
},
{
"_id" : ObjectId("51e3a736ea832e98dd545f65"),
"Group" : 2,
"Value" : 7
}
]
},
{
"_id" : 1,
"docs" : [
{
"_id" : ObjectId("51e3a740ea832e98dd545f69"),
"Group" : 1,
"Value" : 21
},
{
"_id" : ObjectId("51e3a2a5ea832e98dd545f63"),
"Group" : 1,
"Value" : 10
},
{
"_id" : ObjectId("51e3a742ea832e98dd545f6a"),
"Group" : 1,
"Value" : 5
},
{
"_id" : ObjectId("51e3a2a3ea832e98dd545f62"),
"Group" : 1,
"Value" : 4
},
{
"_id" : ObjectId("51e3a745ea832e98dd545f6b"),
"Group" : 1,
"Value" : 2
}
]
}
],
"ok" : 1
}
Обновление для MongoDB >= v3.2:
Теперь вы можете добавить этап $project
в конец конвейера агрегации, чтобы ограничить количество элементов в группе:
$project: {
_id: '$_id',
docs: {
$slice: [
'$docs',
3 // max number of elements returned from the start of the array
]
}
}
person
Derick
schedule
15.07.2013