spring-projects / spring-data-mongodb

Provides support to increase developer productivity in Java when using MongoDB. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
https://spring.io/projects/spring-data-mongodb/
Apache License 2.0
1.59k stars 1.07k forks source link

Converter called multiple times evaluating aggregation operation query methods #4712

Closed MrWangGang closed 3 weeks ago

MrWangGang commented 1 month ago

my Converter

@WritingConverter
public class EnumWriteConverter implements Converter<ConverterEnum, String> {
    public EnumWriteConverter() {
    }

    public String convert(ConverterEnum source) {
        return source.getValue();
    }
}

Pass the enumeration as a parameter,my enum impl -> ConverterEnum


    @Aggregation({
            "{$addFields: { '_idString': { $toString: '$_id' } }}",
            "{$match: { userId: ?0 }}",
            "{$lookup: { from: 't_sku_skill', localField: '_idString', foreignField: 'itemId', as: 'skuDetails' }}",
            "{$unwind: { path: '$skuDetails', preserveNullAndEmptyArrays: true }}",
            "{$match: { deletedEnum: ?1 }}",
            "{$sort: { availableEnum: 1 }}", // ASC
            "{$addFields: { quantity: '$skuDetails.quantity' }}",
            "{$project: { _idString: 0, skuDetails: 0 }}"
    })
    Flux<ItemSkillPO.AggregationSku> findBy(String userId, EnumCommerceItemDeletedEnum deleted , Pageable pageable);

"I found that the Converter was called multiple times, and the source was always the same enumeration, ENUM_COMMERCE_ITEM_DELETED_UNDELETE, because I called this query method in the business logic."

   @Override
    public Flux<ItemSkillPO.AggregationSku> page(String userId, Pageable pageable) {
        return repository.findBy(userId,ENUM_COMMERCE_ITEM_DELETED_UNDELETE,pageable);
    }

I only called the query method once, but the Converter was called multiple times. Why?

MrWangGang commented 1 month ago

@spring-projects-issues @nikos @nemtsov @rmorgan

christophstrobl commented 1 month ago

Thank you for reaching out - If you'd like us to spend some time investigating, please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.

MrWangGang commented 1 month ago

I find it difficult to provide samples involving databases; it's very troublesome. Perhaps you could simply set up a project.

Define your converter:

@WritingConverter
public class EnumWriteConverter implements Converter<ConverterEnum, String> {
    public EnumWriteConverter() {
    }

    public String convert(ConverterEnum source) {
        return source.getValue();
    }
}

Define the interface:

public interface ConverterEnum {
    String getDescription();

    @JsonValue
    String getValue();
}

Define the enumeration:

public enum EnumCommerceItemDeletedEnum implements ConverterEnum {
    ENUM_COMMERCE_ITEM_DELETED_DELETE("Delete", "DELETE"),
    ENUM_COMMERCE_ITEM_DELETED_UNDELETE("Undelete", "UNDELETE");

    EnumCommerceItemDeletedEnum(String description, String value) {
        this.description = description;
        this.value = value;
    }

    private final String value;
    private final String description;
}

Then create a Spring Data interface:

@Aggregation({
    "{$addFields: { '_idString': { $toString: '$_id' } }}",
    "{$match: { userId: ?0 }}",
    "{$match: { deletedEnum: ?1 }}",
    "{$count: 'totalCount' }"
})
Mono<Long> count(String userId, EnumCommerceItemDeletedEnum deleted);

You can test two scenarios: one based on @Aggregation and one based on a named method. However, I have tested it before, and using repository.find(Example) does not cause such issues. Only when using @Query or @Aggregation to execute queries with native SQL, the converter gets called multiple times.

MrWangGang commented 1 month ago

@spring-projects-issues

christophstrobl commented 1 month ago

thanks for the feedback - I see the invocations now. there's multiple things contributing to this. we'll look into those.