I have 2 Collections assume as 1 to many relation, e.g. user and comments. requirement is to merge user with their latest comment as single object and return the list of the newly merged object as result.
aggregation works perfect in the mongo console
db.user.aggregate(
{
$addFields:{
cId: {$toString: '$_id'},
user: '$$ROOT'
}
},
{$match: {'invitees': {$elemMatch: {'user.userId': '5e70e82532044a5e4e7cbc8d'}}}},
{$lookup: {
from: 'comment',
let: {'cc': '$cId'},
pipeline: [
{$match: {$expr: {$and: [{$eq: ['$$cc', '$userId']},{$gte: ['$time', '$$NOW']}]}}},
{$sort: {'time': -1}},
{$limit: 1}
],
as: 'next'
}
},
{$unwind: {path: '$next'}},
{
$project: {
_id: 0,
user: 1,
next: 1,
status: {
$map: {
input: {
$filter: {
input: '$invitees',
as: 'item',
cond: {
$eq: ['$$item.user.userId', '$userId']
}
}
},
as: 'invitee',
in: '$$invitee.status'
}
}
}
},
{$unwind: {path: '$status'}},
{$match: {$expr: {$in: ['$status', ['Accepted', 'Pending']]}}},
{$sort: {status: 1}}
)
I tried translating this to spring-data Aggregations but had issues with $toString. then I tried using mongodb java API Aggregations API to run this.
Arrays.asList(
Aggregates.addFields(Arrays.asList(
new Field<>("cId", Document.parse("{$toString: '$_id'}")),
new Field<>("user", "$$ROOT"),
new Field<>("userId", userId)
)
),
Aggregates.match(Filters.elemMatch("invitees", Filters.eq("user.userId", userId))),
Aggregates.lookup(
"comment",
Collections.singletonList(new Variable<>("cc", "$cId")),
Arrays.asList(
Aggregates.match(
Filters.expr(
Filters.and(
Filters.eq("$$cc", "$userId")
))),
Aggregates.sort(Sorts.ascending("time")),
Aggregates.limit(1)
),
"next"
)
);
AggregateIterable<Document> r = mongoClient
.getDatabase("my-db")
.getCollection("user")
.aggregate(l);
receiving error:
Command failed with error 168 (InvalidPipelineOperator): 'Unrecognized expression '$$cc'' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "Unrecognized expression '$$cc'", "code": 168, "codeName": "InvalidPipelineOperator"}
using:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.12.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-core -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<version>3.12.3</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
<version>3.12.3</version>
</dependency>
any suggestion is much appreciated.
The aggregate command in MongoDB is designed with specific goals of improving performance and usability for aggregation tasks. It uses a �pipeline� approach where objects are transformed as they pass through a series of pipeline operators such as $group, $match, and $sort.
What is the Aggregation Pipeline in MongoDB? The aggregation pipeline refers to a specific flow of operations that processes, transforms, and returns results. In a pipeline, successive operations are informed by the previous result. Let's take a typical pipeline: Input -> $match -> $group -> $sort -> output.
The $lookup operator is an aggregation operator or an aggregation stage, which is used to join a document from one collection to a document of another collection of the same database based on some queries. Both the collections should belong to the same databases.
For performing MongoDB Join two collections, you must use the $lookup operator. It is defined as a stage that executes a left outer join with another collection and aids in filtering data from joined documents. For example, if a user requires all grades from all students, then the below query can be written: Students.
I thought the key point is Filters.eq
can not read variables which prefix with $
, like $$cc
or $userId
. I try to rewrite this part and it can work.
Aggregates.match(
Filters.expr(
Filters.and(
new Document("$eq", Arrays.asList("$userId", "$$cc"))
)
)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With