Your example documents are invalid because you have a unique key violation on field _id. For this reason, I have renamed the field to simply id.
Sample Test Data
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
}])
Aside from that, I think you were pretty close, but your GROUP BY clause needs some changes. Here is what I believe to be a working version...
Code Example
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;
}
}
Aggregation Explained
There are 3 stages to this aggregation
- Sort
- Group
- Project
The $sort stage will sort by field id ascending, then by field channelId ascending, then by createdAt descending. This will kind of group the records logically together in the desired order.
The $group stage will group by id and channelId. Because the documents have already been sorted in the first stage we can simply take the first occurrence of a group and retain the other fields (via accumulator $first).
The grouping stage leaves the documents in a less-than-desirable shape. To fix the shape, use a $project to put the documents back into desired shape.
Example output
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}}
Conclusion
It appears there is no additional sorting requirement for the final output, so the natural order where 3 arrives before 2 is OK. If needed, an additional $sort stage could be applied for the final output.