2017-05-26 14 views
0

長い投稿にはお詫び申し上げます!MongoDB - フィールドを指定せずに集約してグループを選択

私は、次の書類をMongoのコレクションを持っている:(順序にはない、私はこれらの文書を照会し、最高値で、各名前のためのエントリを返したい

{ 
    "_id" : ObjectId("592811e3fab9f74b07139d73"), 
    "Name" : "John", 
    "Value" : 1, 
    "AnotherValue": "12345" 
}, 
{ 
    "_id" : ObjectId("592811f8fab9f74b07139d78"), 
    "Name" : "John", 
    "Value" : 5, 
    "AnotherValue": "55555" 
}, 
{ 
    "_id" : ObjectId("59281206fab9f74b07139d7e"), 
    "Name" : "John", 
    "Value" : 12, 
    "AnotherValue": "654321" 

}, 
{ 
    "_id" : ObjectId("59281217fab9f74b07139d81"), 
    "Name" : "Chris", 
    "Value" : 3, 
    "AnotherValue": "11111" 
}, 
{ 
    "_id" : ObjectId("59281223fab9f74b07139d85"), 
    "Name" : "Steve", 
    "Value" : 2, 
    "AnotherValue": "22222" 
}, 
{ 
    "_id" : ObjectId("5928122ffab9f74b07139d87"), 
    "Name" : "Steve", 
    "Value" : 4, 
    "AnotherValue": "33333" 
} 

、ので、私の希望の結果セット問題は)次のとおりです。

{ 
    "_id" : ObjectId("59281206fab9f74b07139d7e"), 
    "Name" : "John", 
    "Value" : 12, 
    "AnotherValue": "654321" 
}, 
{ 
    "_id" : ObjectId("59281217fab9f74b07139d81"), 
    "Name" : "Chris", 
    "Value" : 3, 
    "AnotherValue": "11111" 
}, 
{ 
    "_id" : ObjectId("5928122ffab9f74b07139d87"), 
    "Name" : "Steve", 
    "Value" : 4, 
    "AnotherValue": "33333" 
} 

私は私が使用するC#でまったく同じことをやってみたかった場合:

var result = 
    from item in collection 
    orderby item.Value descending 
    group item by item.Name into itemGroup 
    select itemGroup.First(); 
私が持っているアグリゲーションパイプラインを使用して

は限り:

db.getCollection('test').aggregate(
[ 
    { "$sort" : { "Value" : -1 } }, //sort descendingly by the Value field 
    { "$group" : { "_id" : "$Name", "highest" : { "$first" : "$$ROOT" } } }, //group by name and select the first document in the group (as they are sorted descendingly, this will be the document with the highest value) 
]) 

これは私の次の結果セットできます:あなたが見ることができるように

​​

を、私は、文書の配列を、それぞれが含む持っています名前である「_id」フィールドと、実際のドキュメントである「最高」フィールドとを含む。

これは、C#で表されます:私が知りたいのは何、それは私だけで、実際のユーザー文書ではなく、グループ文書を選択することを確認するために私のパイプラインに別のステップを追加することが可能である

var result = 
    from item in collection 
    orderby item.Value descending 
    group item by item.Name into itemGroup 
    select new { id = itemGroup.Key, highest = itemGroup.First() }; 

これには人物文書が含まれていますが、フィールドを指定せずにこれを行うことはできますか?私はフィールドが知られていないかもしれないようにオブジェクトのさまざまな種類のこのクエリを使用することができるC#クラスを書くことを望んでいる(DOESのためにこのクエリを使用する可能性があるすべてのコレクションは、すべて共通の特性を持っています)。

もし私が完全に間違った方法で来たら、私はまったく新しい提案をすることができます。最後に希望の結果が得られる限り、私は満足しています。

ご協力いただきありがとうございます。

+0

集計は拡張できません。シャーディングでうまくいく。 – arboreal84

+0

MongoDB 3.4をお持ちの場合は、['$ replaceRoot'](https://docs.mongodb.com/manual/reference/operator/aggregation/replaceRoot/)を使用することができます。そうでなければ、すべてのフィールドを' $ project '。それが必要ならばアップグレードしてください。しかし、それは本当に悪いですか?どちらの場合も、集計パイプラインで結果をもう一度実行するか、単に各戻り値をクライアントコードで処理するコストがトレードオフであることがわかります。そのような些細な用法のために、私はクライアントコードでそれをやっています。 –

+0

$ replaceRootは、私が何をしていたかを正確に達成しました。ありがとうございました! –

答えて

0

コメントに私の質問に答えてくれたNeil Lunnに感謝します。

https://docs.mongodb.com/manual/reference/operator/aggregation/replaceRoot/

のMongoDB 3.4は、私が必要とするまさに実現の$ replaceRootパイプラインオプションがあります。

db.getCollection('test').aggregate(
[ 
    { "$sort" : { "Value" : -1 } }, //sort descendingly by the Value field 
    { "$group" : { "_id" : "$Name", "highest" : { "$first" : "$$ROOT" } } }, //group by name and select the first document in the group (as they are sorted descendingly, this will be the document with the highest value) 
    { "$replaceRoot": { newRoot: "$highest" } } 
]) 

結果セット:そうではないので

{ 
    "_id" : ObjectId("5928122ffab9f74b07139d87"), 
    "Name" : "Steve", 
    "Value" : 4 
}, 
{ 
    "_id" : ObjectId("59281217fab9f74b07139d81"), 
    "Name" : "Chris", 
    "Value" : 3 
}, 
{ 
    "_id" : ObjectId("59281206fab9f74b07139d7e"), 
    "Name" : "John", 
    "Value" : 12 
} 
関連する問題