2017-05-26 54 views
0

長篇帖子道歉!MongoDB - 選擇聚合中的組而不指定字段

我有一個蒙戈集合與下列文件:

{ 
    "_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#類,它將能夠使用這個查詢的各種不同類型的對象,所以字段可能不知道(假設我可能想使用這個查詢的每個集合都有名稱和值字段,他們都會有一些共同的屬性)。

如果我以完全錯誤的方式來解決這個問題,那麼我會接受全新的建議。只要我最終達到預期結果,我就會開心。

在此先感謝您的幫助。

+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 
}