MongoDB聚合在Java中具有不同的价值?
Posted
技术标签:
【中文标题】MongoDB聚合在Java中具有不同的价值?【英文标题】:MongoDB aggregation wtih distinct value in Java? 【发布时间】:2021-12-05 14:35:53 【问题描述】:我正在尝试根据唯一 ID 获取最新输入的文档。这是合集
"_id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 8686868,
"channelId" : "909090",
"createdAt": 1
"_id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 8686868,
"channelId" : "909090"
"createdAt": 2
"_id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 10101010,
"channelId" : "919191"
"createdAt": 3
结果将是:
"_id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 8686868,
"channelId" : "909090"
"createdAt": 2
"_id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 10101010,
"channelId" : "919191"
"createdAt": 3
为元素提供独特的channelId
关键字和最新创建的channelId
。
我尝试了以下方法:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.sort(Sort.Direction.DESC, Constant.CREATED_AT),
Aggregation.group(Constant.CHANNEL_ID));
return mongoTemplate.aggregate(aggregation, "tbl_message", Messages.class)
.getMappedResults()
.stream()
.distinct()
.collect(Collectors.toList());
上面的代码只是在整个集合中为我提供了不同的 channelId (s)。如何按要求更正上述说法?
【问题讨论】:
【参考方案1】:您的示例文档无效,因为您在字段 _id
上存在唯一键违规。为此,我将该字段重命名为简单的id
。
样本测试数据
db.collection.insertMany([
"id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 8686868,
"channelId" : "909090",
"createdAt": 1
,
"id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 8686868,
"channelId" : "909090",
"createdAt": 2
,
"id" : "535f5d074f075c37fff4cc74",
"senderId" : 8989898,
"receiverId" : 10101010,
"channelId" : "919191",
"createdAt": 3
])
除此之外,我认为您非常接近,但是您的 GROUP BY
子句需要一些更改。这是我认为可以工作的版本...
代码示例
package test.barry;
public class Main
public static void main(String[] args)
com.mongodb.client.MongoClient client = connectToReplicaSet();
com.mongodb.client.MongoDatabase db = client.getDatabase("barrydb");
com.mongodb.client.MongoCollection<org.bson.Document> collection = db.getCollection("collection");
com.mongodb.client.AggregateIterable<org.bson.Document> iterable1 = collection.aggregate(
java.util.Arrays.asList(
com.mongodb.client.model.Aggregates.sort(com.mongodb.client.model.Sorts.orderBy(com.mongodb.client.model.Sorts.ascending("id"), com.mongodb.client.model.Sorts.ascending("channelId"), com.mongodb.client.model.Sorts.descending("createdAt"))),
com.mongodb.client.model.Aggregates.group(
new org.bson.BsonDocument("id", new org.bson.BsonString("$id")).append("channelId", new org.bson.BsonString("$channelId")),
com.mongodb.client.model.Accumulators.first("senderId", "$senderId"),
com.mongodb.client.model.Accumulators.first("receiverId", "$receiverId"),
com.mongodb.client.model.Accumulators.first("createdAt", "$createdAt"),
com.mongodb.client.model.Accumulators.first("originalId", "$_id")
),
com.mongodb.client.model.Aggregates.project(
com.mongodb.client.model.Projections.fields(
com.mongodb.client.model.Projections.computed("_id", "$originalId"),
com.mongodb.client.model.Projections.computed("id", "$_id.id"),
com.mongodb.client.model.Projections.include("senderId", "receiverId"),
com.mongodb.client.model.Projections.computed("channelId", "$_id.channelId"),
com.mongodb.client.model.Projections.include("createdAt")
)
)
)
);
// AUTO-CLOSABLE TRY
try(com.mongodb.client.MongoCursor<org.bson.Document> cursor1 = iterable1.iterator())
while (cursor1.hasNext())
org.bson.Document queriedDocument1 = cursor1.next();
System.out.println(String.format("queriedDocument1: %s", queriedDocument1));
private static com.mongodb.client.MongoClient connectToReplicaSet()
java.util.ArrayList<com.mongodb.ServerAddress> hosts = new java.util.ArrayList<com.mongodb.ServerAddress>();
hosts.add(new com.mongodb.ServerAddress("localhost", 50011));
hosts.add(new com.mongodb.ServerAddress("localhost", 50012));
hosts.add(new com.mongodb.ServerAddress("localhost", 50013));
com.mongodb.MongoCredential mongoCredential = com.mongodb.MongoCredential.createScramSha256Credential("testuser", "admin", "mysecret".toCharArray());
com.mongodb.MongoClientSettings mongoClientSettings = com.mongodb.MongoClientSettings.builder()
.applyToClusterSettings(clusterSettingsBuilder -> clusterSettingsBuilder.hosts(hosts).requiredReplicaSetName("replSet"))
.credential(mongoCredential)
.writeConcern(com.mongodb.WriteConcern.MAJORITY)
.readConcern(com.mongodb.ReadConcern.MAJORITY)
.readPreference(com.mongodb.ReadPreference.primary())
.retryWrites(true)
.build();
com.mongodb.client.MongoClient client = com.mongodb.client.MongoClients.create(mongoClientSettings);
return client;
聚合解释
这个聚合有 3 个阶段
-
排序
组
项目
$sort
阶段将按字段id
升序排序,然后按字段channelId
升序排序,然后按createdAt
降序排序。这会将记录按所需的顺序逻辑地组合在一起。
$group
阶段将由id
和channelId
分组。因为文档已经在第一阶段排序,我们可以简单地取组的第一次出现并保留其他字段(通过累加器$first
)。
分组阶段使文档的形状不太理想。要修复形状,请使用$project
将文档恢复为所需的形状。
示例输出
queriedDocument1: DocumentsenderId=8989898, receiverId=10101010, createdAt=3, _id=616d9387719033ca154188a2, id=535f5d074f075c37fff4cc74, channelId=919191
queriedDocument1: DocumentsenderId=8989898, receiverId=8686868, createdAt=2, _id=616d9387719033ca154188a1, id=535f5d074f075c37fff4cc74, channelId=909090
结论
看起来对最终输出没有额外的排序要求,因此 3 在 2 之前到达的自然顺序是可以的。如果需要,可以为最终输出应用额外的$sort
阶段。
【讨论】:
以上是关于MongoDB聚合在Java中具有不同的价值?的主要内容,如果未能解决你的问题,请参考以下文章