2017-05-26 49 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 
}