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.61k stars 1.08k forks source link

`$all` on `_id` leads to Exception if Collection with one element is passed #4736

Closed YuriiAndreitsev closed 1 month ago

YuriiAndreitsev commented 3 months ago

if one element in Collection is passed in .all() criteria it is not preserved as array in spring-data-mongodb higher that 4.3.0

image

image

christophstrobl commented 3 months ago

Thank you for getting in touch. Please do not upload images but take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem. Thank you!

YuriiAndreitsev commented 3 months ago

okay, sorry for that, i will take a note of that,

i've debugged a little bit, it look like in this method it skips in the first phase it skips if ("$nin".equals(key) || "$in".equals(key)) and in result recursively converts objectId from array with single element into one objectId and of course it becomes invalid for $all operator

`

      private Object convertIdField(Field documentField, Object source) {

    Object value = source;
    if (isDBObject(source)) {
        DBObject valueDbo = (DBObject) source;
        value = new Document(valueDbo.toMap());
    }

    if (!isDocument(value)) {
        return convertId(value, getIdTypeForField(documentField));
    }

    Document valueDbo = (Document) value;
    Document resultDbo = new Document(valueDbo);

    for (Entry<String, Object> entry : valueDbo.entrySet()) {

        String key = entry.getKey();
        if ("$nin".equals(key) || "$in".equals(key)) {
            List<Object> ids = new ArrayList<>();
            for (Object id : (Iterable<?>) valueDbo.get(key)) {
                ids.add(convertId(id, getIdTypeForField(documentField)));
            }
            resultDbo.put(key, ids);
        } else if (isKeyword(key)) {
            resultDbo.put(key, convertIdField(documentField, entry.getValue()));
        } else {
            if (documentField.getProperty() != null && documentField.getProperty().isEntity()) {
                Field propertyField = createPropertyField(documentField.getPropertyEntity(), key, mappingContext);
                resultDbo.put(key, getMappedValue(propertyField, entry.getValue()));
            } else {
                resultDbo.put(key, getMappedValue(documentField, entry.getValue()));
            }
        }
    }

    return resultDbo;
}`
christophstrobl commented 3 months ago

Thank you @YuriiAndreitsev - I was able to reproduce the issue. We'll have a closer look!