Skip to main content

Java MongoTemplate - Adding addFields in Aggregation Operations

Working with mongoTemplate to operate MongoDB is full of pitfalls - the examples in the Spring Boot official documentation don't meet real-world requirements.

Scenario

I have a MongoDB query like this, where the _id from the wallpaper document is associated with wallpaper_id from the wallpaper_get_success document:

db.wallpaper.aggregate([
{
$addFields: {
"_id": {
"$toString": "$_id"
}
}
},
{
"$lookup": {
"from": "wallpaper_get_success",
"localField": "_id",
"foreignField": "wallpaper_id",
"as": "success_id"
}
},
{
"$match": {
"success_id": {
"$ne": []
}
}
},
{
"$sample": {
"size": 5
}
}
])

The following section is essential because of this issue: MongoDB join query - localField using _id for matching doesn't work

{
$addFields: {
"_id": {
"$toString": "$_id"
}
}
}

But while the database operation is straightforward SQL, converting it to Java code is painful. In newAggregation, lookup, match, and sample operations all work, but addFields doesn't:

Aggregation aggregation = newAggregation(
Aggregation.fields(""), // This part is problematic
lookup("wallpaper_get_success", "_id", "wallpaper_id", "success_id"),
match(Criteria.where("success_id").ne(new WallpaperGetSuccess[]{})),
sample(5)
);

image.png

There's almost no information online about this operation. I finally found the answer on StackOverflow.

Solution

Original post: How can I implement addFields mongoDB query in Java

The solution is to change addFields to new Document.

Key point: The imported Document class should be from org.bson, not from spring-boot-data-mongo:

import org.bson.Document;

Code:

import org.bson.Document; // Key import
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Component;

Aggregation aggregation = newAggregation(
aoc -> new Document("$addFields",new Document("_id",new Document("$toString","$_id"))),
lookup("wallpaper_get_success", "_id", "wallpaper_id", "success_id"),
match(Criteria.where("success_id").ne(new WallpaperGetSuccess[]{})),
sample(5)
);

You can also avoid using lambda expressions, like this:

image.png

Here's a comparison between the native SQL and Java code:

image.png