Fix issue with reference conversion in updates.

We now make sure to convert references in update operations targeting collection like fields when using eg. the push modifier.

Closes #4041
Original pull request: #4045.
This commit is contained in:
Christoph Strobl
2022-05-06 14:33:42 +02:00
committed by Mark Paluch
parent f7cf23510c
commit 5f33987741
2 changed files with 44 additions and 1 deletions

View File

@@ -15,8 +15,10 @@
*/
package org.springframework.data.mongodb.core.convert;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import org.bson.Document;
@@ -34,6 +36,7 @@ import org.springframework.data.mongodb.core.query.Update.Modifiers;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
* A subclass of {@link QueryMapper} that retains type information on the mongo types.
@@ -221,8 +224,18 @@ public class UpdateMapper extends QueryMapper {
: getMappedSort(sortObject, field.getPropertyEntity());
}
TypeInformation<?> typeHint = field == null ? ClassTypeInformation.OBJECT : field.getTypeHint();
if (isAssociationConversionNecessary(field, value)) {
if (ObjectUtils.isArray(value) || value instanceof Collection) {
List<Object> targetPointers = new ArrayList<>();
for (Object val : converter.getConversionService().convert(value, List.class)) {
targetPointers.add(getMappedValue(field, val));
}
return targetPointers;
}
return super.getMappedValue(field, value);
}
TypeInformation<?> typeHint = field == null ? ClassTypeInformation.OBJECT : field.getTypeHint();
return converter.convertToMongoType(value, typeHint);
}

View File

@@ -903,6 +903,29 @@ public class MongoTemplateDocumentReferenceTests {
assertThat(target).containsEntry("toB", "b");
}
@Test // GH-4041
void updateReferenceWithPushToCollection() {
WithListOfRefs a = new WithListOfRefs();
a.id = "a";
template.save(a);
WithListOfRefs b = new WithListOfRefs();
b.id = "b";
template.save(b);
template.update(WithListOfRefs.class).matching(where("id").is(a.id))
.apply(new Update().push("refs").each(new Object[] { b })).first();
String collection = template.getCollectionName(WithListOfRefs.class);
Document target = template.execute(db -> {
return db.getCollection(collection).find(Filters.eq("_id", "a")).first();
});
assertThat(target).containsEntry("refs", Collections.singletonList("b"));
}
@Test // GH-3782
void updateReferenceHavingCustomizedIdTargetType() {
@@ -1584,4 +1607,11 @@ public class MongoTemplateDocumentReferenceTests {
return publisher;
}
}
@Data
public static class WithListOfRefs {
@Id private String id;
@DocumentReference private List<WithListOfRefs> refs;
}
}