2017-06-16 110 views
0

我正在嘗試新建mongodb,並嘗試爲集合mytest1中的學生拔出具有最高標記的文檔,並在下方形成了一個查詢。基於關鍵值對文檔進行排序和排序?

{ 
     "_id" : ObjectId("5943b63496459374d40da429"), 
     "name" : "Person1", 
     "marks" : 20 
    }, 
    { 
     "_id" : ObjectId("5943b65196459374d40da43a"), 
     "name" : "Person2", 
     "marks" : 20 
    }, 
    { 
     "_id" : ObjectId("5943b65196459374d40da43c"), 
     "name" : "Person1", 
     "marks" : 30 
    }, 
    { 
     "_id" : ObjectId("5943b6d696459374d40da47a"), 
     "name" : "Person1", 
     "marks" : 25 
    }, 
    { 
     "_id" : ObjectId("5943b6d696459374d40da47c"), 
     "name" : "Person2", 
     "marks" : 50 
    }, 
    { 
     "_id" : ObjectId("5943b6d696459374d40da47e"), 
     "name" : "Person1", 
     "marks" : 90 
    }, 
    { 
     "_id" : ObjectId("5943b6d696459374d40da480"), 
     "name" : "Person3", 
     "marks" : 990 
    } 

查詢:

 db.mytest1.aggregate([   
     { $sort : { "name" : 1,"marks" : -1} }, 
      {$group: 
      { 
       _id: "$name", 
       name: { $first: "$name" }, 
       marks: { $first: "$marks" } 
     }} 
]) 
  1. 有沒有更好的方式來做到這一點?
  2. 如果我的方案是基於標記對文檔進行編號,我該如何實現它?

結果:

 {"name" : "Person1","marks" : 30,"rank" : 1} 
    {"name" : "Person1","marks" : 25,"rank" : 2} 
    {"name" : "Person1","marks" : 20,"rank" : 3} 
    {"name" : "Person2","marks" : 50,"rank" : 1} 
    {"name" : "Person2","marks" : 20,"rank" : 2} 
    {"name" : "Person3","marks" : 990,"rank" : 3} 

回答

1

我真的認爲這是最實際的,簡單的遊標的迭代,但後來更多。

使用聚合框架「小」集團將利用從$unwindincludeArrayIndex用MongoDB的3.2中引入最快的可行之路:

db.mytest1.aggregate([ 
    { "$sort": { "name" : 1,"marks" : -1} }, 
    { "$group": { 
    "_id": "$name", 
    "items": { "$push": "$$ROOT" } 
    }}, 
    { "$unwind": { "path": "$items", "includeArrayIndex": "items.rank" } }, 
    { "$replaceRoot": { "newRoot": "$items" } }, 
    { "$sort": { "name" : 1,"marks" : -1} } 
]) 

主要生產:

{ "name" : "Person1", "marks" : 90, "rank" : NumberLong(0) } 
{ "name" : "Person1", "marks" : 30, "rank" : NumberLong(1) } 
{ "name" : "Person1", "marks" : 25, "rank" : NumberLong(2) } 
{ "name" : "Person1", "marks" : 20, "rank" : NumberLong(3) } 
{ "name" : "Person2", "marks" : 50, "rank" : NumberLong(0) } 
{ "name" : "Person2", "marks" : 20, "rank" : NumberLong(1) } 
{ "name" : "Person3", "marks" : 990, "rank" : NumberLong(0) } 

或者去一點點長:

db.mytest1.aggregate([ 
    { "$sort": { "name" : 1,"marks" : -1} }, 
    { "$group": { 
    "_id": "$name", 
    "items": { "$push": "$$ROOT" } 
    }}, 
    { "$unwind": { "path": "$items", "includeArrayIndex": "items.rank" } }, 
    { "$project": { 
    "_id": 0, 
    "name": "$items.name", 
    "marks": "$items.marks", 
    "rank": { "$add": [ "$items.rank", 1 ] } 
    }}, 
    { "$sort": { "name" : 1,"marks" : -1} } 
]) 

佤你想要的。

{ "name" : "Person1", "marks" : 90, "rank" : 1 } 
{ "name" : "Person1", "marks" : 30, "rank" : 2 } 
{ "name" : "Person1", "marks" : 25, "rank" : 3 } 
{ "name" : "Person1", "marks" : 20, "rank" : 4 } 
{ "name" : "Person2", "marks" : 50, "rank" : 1 } 
{ "name" : "Person2", "marks" : 20, "rank" : 2 } 
{ "name" : "Person3", "marks" : 990, "rank" : 1 } 

但要小心,因爲我們將所有內容放入「分組」中,以便在提取時獲得「索引」位置。這對小列表來說很好,但是你永遠不會用數千個項目來嘗試它。

對於項目的1000年再重複在休息光標和排名,而不是:

var current = null, 
    rank = 0; 

db.mytest1.find().sort({ "name": 1, "marks": -1 }).forEach(doc => { 
    if (doc.name != current || current == null) { 
    rank = 0; 
    current = doc.name; 
    } 
    rank++; 
    doc.rank = rank; 
    delete doc._id; 
    printjson(doc); 
}) 

這是同樣的結果:

{ "name" : "Person1", "marks" : 90, "rank" : 1 } 
{ "name" : "Person1", "marks" : 30, "rank" : 2 } 
{ "name" : "Person1", "marks" : 25, "rank" : 3 } 
{ "name" : "Person1", "marks" : 20, "rank" : 4 } 
{ "name" : "Person2", "marks" : 50, "rank" : 1 } 
{ "name" : "Person2", "marks" : 20, "rank" : 2 } 
{ "name" : "Person3", "marks" : 990, "rank" : 1 } 

所以真的,你可能也只是做到這一點,因爲它的非常簡單和快速。