Skip to content

ComparisonOperators.Eq#equalToValue doesn't work well with Lists [DATAMONGO-2513] #3367

Description

@spring-projects-issues

Sergey Derugo opened DATAMONGO-2513 and commented

There is MongoDB aggregation query

{
    [
        {
            "$match": {
                "refId": {"$in": ["x", "y"]}
            }
        },
        {
            "$group": {
                "_id": "$code",
                "origin": {"$addToSet": "$refId"}
            }
        }, {
        "$project":
            {
                "foo": {
                    "$cond": {
                        "if": {
                            "$eq": ["$origin", ["y"]]
                        },
                        "then": 1,
                        "else": 0
                    }
                }
            }
    }
    ]
}

I try to create it using the Spring Data

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.ComparisonOperators;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators;
import org.springframework.data.mongodb.core.query.Criteria;

import java.util.List;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

public class AggregationQueryTest {
    private static final String EXPECTED = "{ \"aggregate\" : \"__collection__\", \"pipeline\" : [" +
            "{ \"$match\" : { \"refId\" : { \"$in\" : [\"x\", \"y\"]}}}, " +
            "{ \"$group\" : { \"_id\" : \"$code\", \"origin\" : { \"$addToSet\" : \"$refId\"}}}, " +
            "{ \"$project\" : { \"foo\" : { \"$cond\" : { \"if\" : { \"$eq\" : [\"$origin\", [\"y\"]]}, \"then\" : 1, \"else\" : 0}}}}" +
            "], \"allowDiskUse\" : true}";

    @Test
    public void checkListEncoding() {
        String current = "x";
        String previous = "y";
        List<?> listParam = List.of(previous); //This doesn't work as expected
        //List<?> listParam = List.of(List.of(previous)); //this is workaround to address the issue

        Aggregation aggregation = Aggregation.newAggregation(
                match(Criteria.where("refId").in(current, previous)),
                group("code")
                        .addToSet("refId").as("origin"),
                project()
                        .and(ConditionalOperators.when(ComparisonOperators.Eq.valueOf("origin").equalToValue(listParam))
                                .then(1)
                                .otherwise(0)).as("foo")
        ).withOptions(AggregationOptions.builder().allowDiskUse(true).build());

        Assertions.assertThat(aggregation.toString()).contains("[\"y\"]").isEqualTo(EXPECTED);
    }
}

Actual result: list parameter is passed to Mong as single value "y" instead of array ["y"]. As a result the query doesn't work properly.
Expected result: list parameter is encoded properly and passed to MongoDB.
Known workaround - wrap list to another list, for example, List.of(List.of(yourValue));


Affects: 2.2.6 (Moore SR6)

Referenced from: pull request #855

Backported to: 2.2.7 (Moore SR7)

Metadata

Metadata

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions