Description
With 4.0.1, specifically #4240, it's not possible to use Spring AggregationExpression
in $map
of $project
stage. A org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for CodecCacheKey{clazz=class org.springframework.data.mongodb.core.aggregation.ConditionalOperators$IfNull
is thrown. It is not specific to IfNull
tho.
What I want to achieve:
document in mongodb:
{
"_id": ObjectId("..."),
"attributes": [
{
"text": {
"de": "DE",
"en": "EN"
}
},
{
"text": {
"en": "EN 2"
}
}
]
}
Desired result
[
{
"_id": ObjectId("..."),
"attributes": [
{
"text": "DE"
},
{
"text": "EN 2"
}
]
}
]
with following aggregation:
db.collection.aggregate([
{
"$project": {
"_id": 1,
"attributes": {
"$map": {
"input": "$attributes",
"as": "attribute",
"in": {
"text": {
"$ifNull": [
"$$attribute.text.de",
"$$attribute.text.en"
]
}
}
}
}
}
}
])
With 4.0.0:
var attributeProjection = VariableOperators.Map
.itemsOf("attributes")
.as("attribute")
.andApply(ctx -> new Document("text",
ifNull("$$attribute.text.de").thenValueOf("$$attribute.text.en")));
var aggregation = new TypedAggregation<>(Entity.class,
project("_id")
.and(attributeProjection).as("attributes")
);
List<EntityProjection> results = mongoTemplate.aggregate(aggregation, EntityProjection.class)
.getMappedResults();
With 4.0.1:
var aggregation = new TypedAggregation<>(Entity.class,
project("_id")
.and(ctx -> new Document("$map",
new Document("input", "$attributes")
.append("as", "attribute")
.append("in", new Document("text",
new Document("$ifNull", new ArrayList<>(
List.of("$$attribute.text.de", "$$attribute.text.en")))
)
)))
.as("attributes")
);
List<EntityProjection> results = mongoTemplate.aggregate(aggregation, EntityProjection.class)
.getMappedResults();
I attached an example project to reproduce the scenario. With Spring Boot 3.0.1, both tests will pass, with >3.0.1 one will fail.
my analysis
With 4.0.1 - because of #4240 - the pipeline is not mapped anymore in AggregationUtil::createPipeline
.
While I still can achieve my desired outcome, I still wanted to bring this up as it feels like a breaking change. But maybe what I did until 4.0.0 was not the "right" way to begin with? In that case I'd be happy for pointers how I should solve my problem with Spring Data MongoDB.
spring-data-mongodb-agg-project-map.zip