您的示例文档无效,因为您在字段 _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: 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 阶段。