Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom converter not used in aggregation pipeline after $replaceRoot stage #4285

Closed
banhidizoli opened this issue Feb 6, 2023 · 7 comments
Closed
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged

Comments

@banhidizoli
Copy link

banhidizoli commented Feb 6, 2023

Hi,

We observed this issue after migrating from 3.4.2 to 4.0.1
We are using a custom converter for mapping ZonedDateTime to Date and vice versa. With the old version our aggregation worked fine, after upgrading we received the following exception:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for CodecCacheKey{clazz=class java.time.ZonedDateTime, types=null}.

Our aggregation is using a $match stage in the pipeline right after $replaceRoot; in this $match, we compare to a ZonedDateTime vale. This should work properly, as we registered a custom converter for this type.

After some debug, we think that this was introduced by Avoid multiple mapping iterations.

Second mapping iteration is needed, because Aggregation#toPipeline method internally looses the initial RelaxedTypeBasedAggregationOperationContext after Aggregation#replaceRoot (after this stage the NoOpAggregationOperationContext is used, which doesn't seem to pick up the custom converters).

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 6, 2023
@mp911de
Copy link
Member

mp911de commented Feb 6, 2023

Would you happen to have an example handy that reproduces your use case?

@mp911de mp911de added the status: waiting-for-feedback We need additional information before we can continue label Feb 6, 2023
@banhidizoli
Copy link
Author

banhidizoli commented Feb 7, 2023

My domain class looks like

@Document(collection = "entity")
public class Entity {

    private String entityId;
    private ZonedDateTime createdDate;
    private int version;
    
    // Getters and setters
}

And the failing aggregation is

var aggregation = Aggregation.newAggregation(
    Aggregation.sort(Direction.DESC, "version"),
    Aggregation.group("entityId")
        .first(Aggregation.ROOT).as("value"),
    Aggregation.replaceRoot("value"),
    Aggregation.match(Criteria.where("createdDate").lt(ZonedDateTime.now())) // here is the problem
);

return mongoTemplate
    .aggregate(aggregation, Entity.class, MutableObject.class)
    .getMappedResults()
    .stream()
    .map(MutableObject<String>::getValue)
    .collect(Collectors.toSet());

And my custom convertor is

public static class ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {
    public static final ZonedDateTimeToDateConverter INSTANCE = new ZonedDateTimeToDateConverter();

    private ZonedDateTimeToDateConverter() {
    }

    @Override
    public Date convert(ZonedDateTime source) {
        return source == null ? null : Date.from(source.toInstant());
    }
}

The custom convertor is registered like

@Configuration
@EnableMongoRepositories("my.package")
public class DatabaseConfiguration extends MongoConfigurationSupport {

    @Override
    protected void configureConverters(MongoCustomConversions.MongoConverterConfigurationAdapter converterConfigurationAdapter) {
        var converters = new ArrayList<Converter<?, ?>>();
        converters.add(ZonedDateTimeToDateConverter.INSTANCE);
        converterConfigurationAdapter.registerConverters(converters);
    }

    @Override
    protected String getDatabaseName() {
        return "myDb";
    }
}

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 7, 2023
@banhidizoli
Copy link
Author

We had to downgrade to version 4.0.0 because of this bug. Is there any estimate of when this will be fixed?

@vladpetrican
Copy link

Are there any updates regarding this issue ?

@csmager
Copy link

csmager commented May 5, 2023

I've also come across this issue in as a breaking change in 3.4.7, which is the same change that causes this: #4240.

The first issue I had was because the mapping hasn't happened when this check occurs to see if the last pipeline stage is $out or $merge. I get this stack trace:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class XXXX.
        at org.bson.internal.CodecCache.lambda$getOrThrow$1(CodecCache.java:52)
        at java.base/java.util.Optional.orElseThrow(Optional.java:403)
        at org.bson.internal.CodecCache.getOrThrow(CodecCache.java:51)
        at org.bson.internal.OverridableUuidRepresentationCodecRegistry.get(OverridableUuidRepresentationCodecRegistry.java:72)
        at org.bson.internal.ChildCodecRegistry.get(ChildCodecRegistry.java:52)
        at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:209)
        at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:168)
        at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:44)
        at org.bson.internal.LazyCodec.encode(LazyCodec.java:38)
        at org.bson.codecs.EncoderContext.encodeWithChildContext(EncoderContext.java:91)
        at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:210)
        at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:168)
        at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:44)
        at org.bson.BsonDocumentWrapper.getUnwrapped(BsonDocumentWrapper.java:199)
        at org.bson.BsonDocumentWrapper.containsKey(BsonDocumentWrapper.java:124)
        at com.mongodb.client.internal.AggregateIterableImpl.getOutNamespace(AggregateIterableImpl.java:240)
        at com.mongodb.client.internal.AggregateIterableImpl.asReadOperation(AggregateIterableImpl.java:203)
        at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
        at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
        at com.mongodb.client.internal.MongoIterableImpl.forEach(MongoIterableImpl.java:121)
        at com.mongodb.client.internal.MappingIterable.forEach(MappingIterable.java:59)
        at com.mongodb.client.internal.MappingIterable.into(MappingIterable.java:69)
        at org.springframework.data.mongodb.core.MongoTemplate.lambda$doAggregate$24(MongoTemplate.java:2268)
        at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:579)
        at org.springframework.data.mongodb.core.MongoTemplate.doAggregate(MongoTemplate.java:2225)
        at org.springframework.data.mongodb.core.MongoTemplate.doAggregate(MongoTemplate.java:2193)
        at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:2187)
        at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:2081)

I then tried ensuring this stage wasn't last in the pipeline. I then ran into the issue noted here as the previous stage was $replaceRoot.

@banhidizoli
Copy link
Author

This problem is stopping us from upgrading to latest version. @mp911de is there any plan to fix this? Or we'll have to adapt to this limitation?

@pbeltechi
Copy link

This issue seems to be solved on 4.2.1 version. Just checked it today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

6 participants