2013-07-14 44 views
1

我有一個MongoDB的集合與該格式的文檔:集團,並採取各組的頂部K的聚集framwork

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

等等...

給定的X,Y和K,I想用聚合框架執行以下操作:

  • 由012選擇與X和Y
  • 集團之間的Group財產的所有文件財產
  • 各組:只挑其中最大Value財產

如何做到這一點的任何想法K個文件?

回答

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 + $ 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 
     ] 
    } 
} 
+0

好主意。切片完成這項工作 –

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" } } 
 
]);