【问题标题】:MongoDB aggregation wtih distinct value in Java?MongoDB聚合在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)。如何按要求更正上述说法?

【问题讨论】:

    标签: mongodb spring-boot mongodb-query aggregation-framework aggregation


    【解决方案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 个阶段

    1. 排序
    2. 项目

    $sort 阶段将按字段id 升序排序,然后按字段channelId 升序排序,然后按createdAt 降序排序。这会将记录按所需的顺序逻辑地组合在一起。

    $group 阶段将由idchannelId 分组。因为文档已经在第一阶段排序,我们可以简单地取组的第一次出现并保留其他字段(通过累加器$first)。

    分组阶段使文档的形状不太理想。要修复形状,请使用$project 将文档恢复为所需的形状。

    示例输出

    queriedDocument1: Document{{senderId=8989898, receiverId=10101010, createdAt=3, _id=616d9387719033ca154188a2, id=535f5d074f075c37fff4cc74, channelId=919191}}
    queriedDocument1: Document{{senderId=8989898, receiverId=8686868, createdAt=2, _id=616d9387719033ca154188a1, id=535f5d074f075c37fff4cc74, channelId=909090}}
    

    结论

    看起来对最终输出没有额外的排序要求,因此 3 在 2 之前到达的自然顺序是可以的。如果需要,可以为最终输出应用额外的$sort 阶段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 2022-06-15
      • 2019-05-29
      • 2018-05-25
      • 1970-01-01
      • 2013-04-28
      相关资源
      最近更新 更多