2013-07-14 1 views
1

У меня есть коллекция MongoDB с документами в этом формате:Group и взять верхние К каждой группе с агрегацией framwork

{ "_id":..., "Group": 1, "Value": 4 } 
{ "_id":..., "Group": 2, "Value": 8 } 
{ "_id":..., "Group": 1, "Value": 10 } 

и так далее ...

Учитывая X, Y и K, I хотели бы использовать структуру агрегации, чтобы сделать следующее:

  • Выберите все документы с Group имущества между X и Y
  • группы, по Group свойство
  • В каждой группе: выбрать только K документы с наибольшим Value собственности

Любая идея о том, как сделать это?

ответ

7

Первые два шага достаточно легко:

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 + $ срез в структуре агрегации. Единственное, что мы можем сделать, это еще одна группа поэтому приложение может выбрать вне 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 
     ] 
    } 
} 
+0

Хорошая идея. Slice выполняет работу –

0

принимают N:

db.rec_log.aggregate([ 
 
    { $match: { uid: { $in: [ "zxf-1", "zxf-2" ] } } }, 
 
    { $sort: { uid: 1, c_date: -1 } }, 
 
    { $group: { _id: '$uid', docs: { $push: { content: '$content' } } } }, 
 
    { $project: { _id: '$_id', docs: { $slice: [ '$docs', 2 ] } } } 
 
]);

принять один:

db.rec_log.aggregate([ 
 
    { $match: { uid: { $in: [ "zxf-1", "zxf-2" ] } } }, 
 
    { $sort: { uid: 1, c_date: -1 } }, 
 
    { $group: { _id: '$uid', docs: { $push: { content: '$content' } } } }, 
 
    { $project: { _id: '$_id', docs0: { $arrayElemAt: ["$docs", 0] } } }, 
 
    { $project: { _id: '$_id', latest_content: "$docs0.content" } } 
 
]);

Смежные вопросы