Skip to content

Commit 4d61d1a

Browse files
committed
Fix _id generation of upserts when _id is part of a selector bwaldvogel#208
1 parent c289757 commit 4d61d1a

2 files changed

Lines changed: 53 additions & 3 deletions

File tree

‎core/src/main/java/de/bwaldvogel/mongo/backend/AbstractMongoCollection.java‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Iterator;
1010
import java.util.LinkedHashSet;
1111
import java.util.List;
12+
import java.util.Map;
1213
import java.util.Objects;
1314
import java.util.Set;
1415
import java.util.TreeSet;
@@ -666,12 +667,26 @@ private Document handleUpsert(Document updateQuery, Document selector, ArrayFilt
666667
*/
667668
Document convertSelectorToDocument(Document selector) {
668669
Document document = new Document();
669-
for (String key : selector.keySet()) {
670-
if (key.startsWith("$")) {
670+
for (Map.Entry<String, Object> entry : selector.entrySet()) {
671+
String key = entry.getKey();
672+
Object value = entry.getValue();
673+
674+
if (key.equals("$and")) {
675+
List<Document> andValues = (List<Document>) value;
676+
for (Document andValue : andValues) {
677+
document.putAll(convertSelectorToDocument(andValue));
678+
}
679+
continue;
680+
} else if (key.equals("$or")) {
681+
List<Document> orValues = (List<Document>) value;
682+
if (orValues.size() == 1) {
683+
document.putAll(convertSelectorToDocument(orValues.get(0)));
684+
}
685+
continue;
686+
} else if (key.startsWith("$")) {
671687
continue;
672688
}
673689

674-
Object value = selector.get(key);
675690
if (!Utils.containsQueryExpression(value)) {
676691
Utils.changeSubdocumentValue(document, key, value, (AtomicReference<Integer>) null);
677692
}

‎test-common/src/main/java/de/bwaldvogel/mongo/backend/AbstractBackendTest.java‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.concurrent.ThreadFactory;
4646
import java.util.concurrent.TimeUnit;
4747
import java.util.regex.Pattern;
48+
import java.util.stream.Stream;
4849

4950
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
5051
import org.bson.BsonInt32;
@@ -65,7 +66,9 @@
6566
import org.junit.jupiter.api.Test;
6667
import org.junit.jupiter.api.TestInfo;
6768
import org.junit.jupiter.params.ParameterizedTest;
69+
import org.junit.jupiter.params.provider.Arguments;
6870
import org.junit.jupiter.params.provider.EnumSource;
71+
import org.junit.jupiter.params.provider.MethodSource;
6972
import org.junit.jupiter.params.provider.ValueSource;
7073
import org.mockito.AdditionalAnswers;
7174
import org.mockito.Mockito;
@@ -1436,6 +1439,38 @@ public void testFindOneAndUpdateWithArrayFilters() {
14361439
.isEqualTo(json("_id: 3, a: {b: [1, 20, 3]}"));
14371440
}
14381441

1442+
private static Stream<Arguments> findAndUpdate_upsert_idInQueryArguments() {
1443+
return Stream.of(
1444+
Arguments.of("_id: 'some value'", false, "_id: 'some value', value: 100"),
1445+
Arguments.of("'$and': [{_id: 'some value'}]", false, "_id: 'some value', value: 100"),
1446+
Arguments.of("'$and': [{_id: 'some value'}, {other: 123}]", false, "_id: 'some value', other: 123, value: 100"),
1447+
Arguments.of("'$or': [{_id: 'some value'}]", false, "_id: 'some value', value: 100"),
1448+
Arguments.of("'$or': [{_id: 'some value'}, {other: 123}]", true, "value: 100"),
1449+
Arguments.of("'$or': [{_id: 'some value', other: 123}]", false, "_id: 'some value', other: 123, value: 100"),
1450+
Arguments.of("'$or': [{_id: 'some value'}, {$and: [{other: 123}, {more: 'abc'}]}]", true, "value: 100"),
1451+
Arguments.of("'$and': [{other: 123}, {$and: [{_id: 'some value'}, {more: 'abc'}]}]", false, "_id: 'some value', other: 123, more: 'abc', value: 100")
1452+
);
1453+
}
1454+
1455+
// https://github.com/bwaldvogel/mongo-java-server/issues/208
1456+
@ParameterizedTest
1457+
@MethodSource("findAndUpdate_upsert_idInQueryArguments")
1458+
void testFindAndUpdate_upsert_idInQuery(String query, boolean randomObjectIdExpected, String expectedDocument) throws Exception {
1459+
collection.findOneAndUpdate(
1460+
json(query),
1461+
json("{'$set': {value: 100}}"),
1462+
new FindOneAndUpdateOptions().upsert(true));
1463+
1464+
if (randomObjectIdExpected) {
1465+
Document document = collection.find().first();
1466+
assertThat(document.remove("_id")).isInstanceOf(ObjectId.class);
1467+
assertThat(document).isEqualTo(json(expectedDocument));
1468+
} else {
1469+
assertThat(collection.find())
1470+
.containsExactly(json(expectedDocument));
1471+
}
1472+
}
1473+
14391474
// https://github.com/bwaldvogel/mongo-java-server/issues/60
14401475
@Test
14411476
public void testUpdateManyWithArrayFilters() {

0 commit comments

Comments
 (0)