我们收集了包含以下字段的“消息”
_id | messageId | chainId | createOn
1 | 1 | A | 155
2 | 2 | A | 185
3 | 3 | A | 225
4 | 4 | B | 226
5 | 5 | C | 228
6 | 6 | B | 300
我们希望按照以下标准选择所有文档字段
所以,预期的结果是
_id | messageId | chainId | createOn
3 | 3 | A | 225
5 | 5 | C | 228
6 | 6 | B | 300
我们在java应用程序中使用spring-data。我尝试采用不同的方法,到目前为止没有任何帮助 是否可以通过单个查询实现上述目标?
答案 0 :(得分:8)
您想要的是使用聚合框架可以实现的功能。 (对其他人有用)的基本形式是:
db.collection.aggregate([
// Group by the grouping key, but keep the valid values
{ "$group": {
"_id": "$chainId",
"docId": { "$first": "$_id" },
"messageId": { "$first": "$messageId" },
"createOn": { "$first": "$createdOn" }
}},
// Then sort
{ "$sort": { "createOn": -1 } }
])
所以"团体"关于" messageId"的明确值同时为每个其他字段取$first
个边界值。或者,如果您想要最大值,则使用$last
代替,但对于最小或最大的行,它可能首先对$sort
有意义,否则只需使用$min
和$max
整行并不重要。
有关使用的更多信息,请参阅MongoDB aggregate()
文档,以及驱动程序JavaDocs和SpringData Mongo连接器文档,以了解聚合方法和可能的帮助程序的更多用法。
答案 1 :(得分:4)
这是使用MongoDB Java驱动程序的解决方案
final MongoClient mongoClient = new MongoClient();
final DB db = mongoClient.getDB("mstreettest");
final DBCollection collection = db.getCollection("message");
final BasicDBObject groupFields = new BasicDBObject("_id", "$chainId");
groupFields.put("docId", new BasicDBObject("$first", "$_id"));
groupFields.put("messageId", new BasicDBObject("$first", "$messageId"));
groupFields.put("createOn", new BasicDBObject("$first", "$createdOn"));
final DBObject group = new BasicDBObject("$group", groupFields);
final DBObject sortFields = new BasicDBObject("createOn", -1);
final DBObject sort = new BasicDBObject("$sort", sortFields);
final DBObject projectFields = new BasicDBObject("_id", 0);
projectFields.put("_id", "$docId");
projectFields.put("messageId", "$messageId");
projectFields.put("chainId", "$_id");
projectFields.put("createOn", "$createOn");
final DBObject project = new BasicDBObject("$project", projectFields);
final AggregationOutput aggregate = collection.aggregate(group, sort, project);
,结果将是:
{ "_id" : 5 , "messageId" : 5 , "createOn" : { "$date" : "2014-04-23T04:45:45.173Z"} , "chainId" : "C"}
{ "_id" : 4 , "messageId" : 4 , "createOn" : { "$date" : "2014-04-23T04:12:25.173Z"} , "chainId" : "B"}
{ "_id" : 1 , "messageId" : 1 , "createOn" : { "$date" : "2014-04-22T08:29:05.173Z"} , "chainId" : "A"}
我用SpringData Mongo尝试过它,当我用chainId对它进行分组时它没有用(java.lang.NumberFormatException:输入字符串:" C")是异常
答案 2 :(得分:0)
替换此行:
final DBObject group = new BasicDBObject("$group", groupFields);
这一个:
final DBObject group = new BasicDBObject("_id", groupFields);
答案 3 :(得分:0)
这是使用springframework.data.mongodb的解决方案:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group("chainId"),
Aggregation.sort(new Sort(Sort.Direction.ASC, "createdOn"))
);
AggregationResults<XxxBean> results = mongoTemplate.aggregate(aggregation, "collection_name", XxxBean.class);