Skip to content

Commit cc44e5f

Browse files
committed
JAVA-2552: Support array filters for update operations in the core driver
1 parent 54454ae commit cc44e5f

File tree

8 files changed

+132
-7
lines changed

8 files changed

+132
-7
lines changed

driver-core/src/main/com/mongodb/bulk/UpdateRequest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import com.mongodb.client.model.Collation;
2020
import org.bson.BsonDocument;
2121

22+
import java.util.List;
23+
2224
import static com.mongodb.assertions.Assertions.notNull;
2325

2426
/**
@@ -33,6 +35,7 @@ public final class UpdateRequest extends WriteRequest {
3335
private boolean isMulti = true;
3436
private boolean isUpsert = false;
3537
private Collation collation;
38+
private List<BsonDocument> arrayFilters;
3639

3740
/**
3841
* Construct a new instance.
@@ -139,5 +142,29 @@ public UpdateRequest collation(final Collation collation) {
139142
this.collation = collation;
140143
return this;
141144
}
145+
146+
/**
147+
* Sets the array filters option
148+
*
149+
* @param arrayFilters the array filters, which may be null
150+
* @return this
151+
* @since 3.6
152+
* @mongodb.server.release 3.6
153+
*/
154+
public UpdateRequest arrayFilters(final List<BsonDocument> arrayFilters) {
155+
this.arrayFilters = arrayFilters;
156+
return this;
157+
}
158+
159+
/**
160+
* Returns the array filters option
161+
*
162+
* @return the array filters, which may be null
163+
* @since 3.6
164+
* @mongodb.server.release 3.6
165+
*/
166+
public List<BsonDocument> getArrayFilters() {
167+
return arrayFilters;
168+
}
142169
}
143170

driver-core/src/main/com/mongodb/operation/BulkWriteBatch.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,13 @@ public void encode(final BsonWriter writer, final WriteRequest writeRequest, fin
358358
BsonDocument collation = update.getCollation().asDocument();
359359
getCodec(collation).encode(writer, collation, EncoderContext.builder().build());
360360
}
361+
if (update.getArrayFilters() != null) {
362+
writer.writeStartArray("arrayFilters");
363+
for (BsonDocument cur: update.getArrayFilters()) {
364+
getCodec(cur).encode(writer, cur, EncoderContext.builder().build());
365+
}
366+
writer.writeEndArray();
367+
}
361368
writer.writeEndDocument();
362369
} else {
363370
DeleteRequest deleteRequest = (DeleteRequest) writeRequest;

driver-core/src/main/com/mongodb/operation/FindAndUpdateOperation.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@
3030
import com.mongodb.internal.validator.UpdateFieldNameValidator;
3131
import com.mongodb.operation.OperationHelper.AsyncCallableWithConnection;
3232
import com.mongodb.operation.OperationHelper.CallableWithConnection;
33+
import org.bson.BsonArray;
3334
import org.bson.BsonBoolean;
3435
import org.bson.BsonDocument;
3536
import org.bson.BsonString;
3637
import org.bson.FieldNameValidator;
3738
import org.bson.codecs.Decoder;
3839

3940
import java.util.HashMap;
41+
import java.util.List;
4042
import java.util.Map;
4143
import java.util.concurrent.TimeUnit;
4244

@@ -48,9 +50,9 @@
4850
import static com.mongodb.operation.DocumentHelper.putIfNotZero;
4951
import static com.mongodb.operation.DocumentHelper.putIfTrue;
5052
import static com.mongodb.operation.OperationHelper.LOGGER;
51-
import static com.mongodb.operation.OperationHelper.validateCollation;
5253
import static com.mongodb.operation.OperationHelper.releasingCallback;
5354
import static com.mongodb.operation.OperationHelper.serverIsAtLeastVersionThreeDotTwo;
55+
import static com.mongodb.operation.OperationHelper.validateCollation;
5456
import static com.mongodb.operation.OperationHelper.withConnection;
5557
import static java.util.concurrent.TimeUnit.MILLISECONDS;
5658

@@ -74,6 +76,7 @@ public class FindAndUpdateOperation<T> implements AsyncWriteOperation<T>, WriteO
7476
private boolean upsert;
7577
private Boolean bypassDocumentValidation;
7678
private Collation collation;
79+
private List<BsonDocument> arrayFilters;
7780

7881
/**
7982
* Construct a new instance.
@@ -326,6 +329,31 @@ public FindAndUpdateOperation<T> collation(final Collation collation) {
326329
return this;
327330
}
328331

332+
333+
/**
334+
* Sets the array filters option
335+
*
336+
* @param arrayFilters the array filters, which may be null
337+
* @return this
338+
* @since 3.6
339+
* @mongodb.server.release 3.6
340+
*/
341+
public FindAndUpdateOperation<T> arrayFilters(final List<BsonDocument> arrayFilters) {
342+
this.arrayFilters = arrayFilters;
343+
return this;
344+
}
345+
346+
/**
347+
* Returns the array filters option
348+
*
349+
* @return the array filters, which may be null
350+
* @since 3.6
351+
* @mongodb.server.release 3.6
352+
*/
353+
public List<BsonDocument> getArrayFilters() {
354+
return arrayFilters;
355+
}
356+
329357
@Override
330358
public T execute(final WriteBinding binding) {
331359
return withConnection(binding, new CallableWithConnection<T>() {
@@ -385,6 +413,9 @@ private BsonDocument getCommand(final ConnectionDescription description) {
385413
if (collation != null) {
386414
commandDocument.put("collation", collation.asDocument());
387415
}
416+
if (arrayFilters != null) {
417+
commandDocument.put("arrayFilters", new BsonArray(arrayFilters));
418+
}
388419
return commandDocument;
389420
}
390421

driver-core/src/test/functional/com/mongodb/operation/FindAndUpdateOperationSpecification.groovy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,26 @@ class FindAndUpdateOperationSpecification extends OperationFunctionalSpecificati
354354
where:
355355
async << [true, false]
356356
}
357+
358+
@IgnoreIf({ !serverVersionAtLeast(3, 5) })
359+
def 'should support array filters'() {
360+
given:
361+
def documentOne = Document.parse('{_id: 1, y: [ {b: 3}, {b: 1}]}')
362+
def documentTwo = Document.parse('{_id: 2, y: [ {b: 0}, {b: 1}]}')
363+
getCollectionHelper().insertDocuments(documentOne, documentTwo)
364+
def update = BsonDocument.parse('{ $set: {"y.$[i].b": 2}}')
365+
def arrayFilters = [BsonDocument.parse('{"i.b": 3}')]
366+
def operation = new FindAndUpdateOperation<Document>(getNamespace(), writeConcern, documentCodec, update)
367+
.returnOriginal(false)
368+
.arrayFilters(arrayFilters)
369+
370+
when:
371+
def result = execute(operation, async)
372+
373+
then:
374+
result == Document.parse('{_id: 1, y: [ {b: 2}, {b: 1}]}')
375+
376+
where:
377+
async << [true, false]
378+
}
357379
}

driver-core/src/test/functional/com/mongodb/operation/MixedBulkWriteOperationSpecification.groovy

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import org.bson.BsonDocument
3737
import org.bson.BsonInt32
3838
import org.bson.BsonObjectId
3939
import org.bson.Document
40+
import org.bson.codecs.BsonDocumentCodec
4041
import org.bson.codecs.DocumentCodec
4142
import org.bson.types.ObjectId
4243
import org.junit.experimental.categories.Category
@@ -880,6 +881,34 @@ class MixedBulkWriteOperationSpecification extends OperationFunctionalSpecificat
880881
async << [true, false]
881882
}
882883

884+
@IgnoreIf({ !serverVersionAtLeast(3, 5) })
885+
def 'should support array filters'() {
886+
given:
887+
def documentOne = BsonDocument.parse('{_id: 1, y: [ {b: 3}, {b: 1}]}')
888+
def documentTwo = BsonDocument.parse('{_id: 2, y: [ {b: 0}, {b: 1}]}')
889+
getCollectionHelper().insertDocuments(documentOne, documentTwo)
890+
def requests = [
891+
new UpdateRequest(new BsonDocument(), BsonDocument.parse('{ $set: {"y.$[i].b": 2}}'), UPDATE)
892+
.arrayFilters([BsonDocument.parse('{"i.b": 3}')]),
893+
new UpdateRequest(new BsonDocument(), BsonDocument.parse('{ $set: {"y.$[i].b": 4}}'), UPDATE)
894+
.multi(true)
895+
.arrayFilters([BsonDocument.parse('{"i.b": 1}')]),
896+
]
897+
def operation = new MixedBulkWriteOperation(namespace, requests, true, ACKNOWLEDGED)
898+
899+
when:
900+
execute(operation, async)
901+
902+
then:
903+
getCollectionHelper().find(new BsonDocumentCodec()) == [
904+
BsonDocument.parse('{_id: 1, y: [ {b: 2}, {b: 4}]}'),
905+
BsonDocument.parse('{_id: 2, y: [ {b: 0}, {b: 4}]}')
906+
]
907+
908+
where:
909+
async << [true, false]
910+
}
911+
883912
private static List<WriteRequest> getTestWrites() {
884913
[new UpdateRequest(new BsonDocument('_id', new BsonInt32(1)),
885914
new BsonDocument('$set', new BsonDocument('x', new BsonInt32(2))),

driver/src/test/unit/com/mongodb/operation/DeleteRequestSpecification.groovy renamed to driver-core/src/test/unit/com/mongodb/operation/DeleteRequestSpecification.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
* Copyright (c) 2008-2014 MongoDB, Inc.
2+
* Copyright 2017 MongoDB, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,

driver/src/test/unit/com/mongodb/operation/InsertRequestSpecification.groovy renamed to driver-core/src/test/unit/com/mongodb/operation/InsertRequestSpecification.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
* Copyright (c) 2008-2014 MongoDB, Inc.
2+
* Copyright 2017 MongoDB, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,

driver/src/test/unit/com/mongodb/operation/UpdateRequestSpecification.groovy renamed to driver-core/src/test/unit/com/mongodb/operation/UpdateRequestSpecification.groovy

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
* Copyright (c) 2008-2014 MongoDB, Inc.
2+
* Copyright 2017 MongoDB, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -116,4 +116,13 @@ class UpdateRequestSpecification extends Specification {
116116
where:
117117
type << [WriteRequest.Type.UPDATE, WriteRequest.Type.REPLACE]
118118
}
119+
120+
def 'should set arrayFilters property'() {
121+
expect:
122+
new UpdateRequest(new BsonDocument(), new BsonDocument(), WriteRequest.Type.UPDATE).arrayFilters(arrayFilters)
123+
.getArrayFilters() == arrayFilters
124+
125+
where:
126+
arrayFilters << [null, [], [new BsonDocument('a.b', new BsonInt32(42))]]
127+
}
119128
}

0 commit comments

Comments
 (0)