2017-06-16 11 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

私は本当にこれは単純なカーソルの反復として最も実用的であると思いますが、より多くのことに後で。

集約フレームワークを使用して「小さな」のグループ化のための最速の実用的な方法は、MongoDBの3.2で導入され$unwindからincludeArrayIndexを使用することになります。

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

In the waあなたは欲しい。

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

だから本当に、あなたにもちょうどそれを行うことができますかなりシンプルで速い。

関連する問題