Skip to content

Commit f3b7ce8

Browse files
iqjumpschristophstrobl
authored andcommitted
DATAMONGO-2218 - Add support for replaceOne operation in BulkOperations.
Original Pull Request: #655
1 parent 24677fa commit f3b7ce8

File tree

4 files changed

+108
-16
lines changed

4 files changed

+108
-16
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/BulkOperations.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
*
3232
* @author Tobias Trelle
3333
* @author Oliver Gierke
34+
* @author Minsu Kim
3435
* @since 1.9
3536
*/
3637
public interface BulkOperations {
@@ -135,6 +136,15 @@ enum BulkMode {
135136
*/
136137
BulkOperations remove(List<Query> removes);
137138

139+
/**
140+
* Add a single replace operation to the bulk operation.
141+
*
142+
* @param query Update criteria.
143+
* @param document the document to replace, must not be {@literal null}.
144+
* @return the current {@link BulkOperations} instance with the replace added, will never be {@literal null}.
145+
*/
146+
BulkOperations replaceOne(Query query, Object document);
147+
138148
/**
139149
* Execute all bulk operations using the default write concern.
140150
*

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultBulkOperations.java

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
import org.bson.Document;
2828
import org.bson.conversions.Bson;
29-
import org.springframework.dao.DataAccessException;
3029
import org.springframework.dao.support.PersistenceExceptionTranslator;
3130
import org.springframework.data.mongodb.core.convert.QueryMapper;
3231
import org.springframework.data.mongodb.core.convert.UpdateMapper;
@@ -38,18 +37,8 @@
3837
import org.springframework.lang.Nullable;
3938
import org.springframework.util.Assert;
4039

41-
import com.mongodb.BulkWriteException;
4240
import com.mongodb.WriteConcern;
43-
import com.mongodb.client.MongoCollection;
44-
import com.mongodb.client.model.BulkWriteOptions;
45-
import com.mongodb.client.model.DeleteManyModel;
46-
import com.mongodb.client.model.DeleteOneModel;
47-
import com.mongodb.client.model.DeleteOptions;
48-
import com.mongodb.client.model.InsertOneModel;
49-
import com.mongodb.client.model.UpdateManyModel;
50-
import com.mongodb.client.model.UpdateOneModel;
51-
import com.mongodb.client.model.UpdateOptions;
52-
import com.mongodb.client.model.WriteModel;
41+
import com.mongodb.client.model.*;
5342

5443
/**
5544
* Default implementation for {@link BulkOperations}.
@@ -58,6 +47,7 @@
5847
* @author Oliver Gierke
5948
* @author Christoph Strobl
6049
* @author Mark Paluch
50+
* @author Minsu Kim
6151
* @since 1.9
6252
*/
6353
class DefaultBulkOperations implements BulkOperations {
@@ -266,6 +256,32 @@ public BulkOperations remove(List<Query> removes) {
266256
return this;
267257
}
268258

259+
/*
260+
* (non-Javadoc)
261+
* @see org.springframework.data.mongodb.core.BulkOperations#replaceOne(org.springframework.data.mongodb.core.query.Query, java.lang.Object)
262+
*/
263+
@Override
264+
public BulkOperations replaceOne(Query query, Object document) {
265+
266+
Assert.notNull(query, "Query must not be null!");
267+
Assert.notNull(document, "Document must not be null!");
268+
269+
ReplaceOptions replaceOptions = new ReplaceOptions();
270+
query.getCollation().map(Collation::toMongoCollation).ifPresent(replaceOptions::collation);
271+
Bson mappedQuery = getMappedQuery(query.getQueryObject());
272+
273+
if (document instanceof Document) {
274+
models.add(new ReplaceOneModel<>(mappedQuery, (Document) document, replaceOptions));
275+
return this;
276+
}
277+
278+
Document sink = new Document();
279+
mongoOperations.getConverter().write(document, sink);
280+
models.add(new ReplaceOneModel<>(mappedQuery, sink, replaceOptions));
281+
282+
return this;
283+
}
284+
269285
/*
270286
* (non-Javadoc)
271287
* @see org.springframework.data.mongodb.core.BulkOperations#executeBulk()

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DefaultBulkOperationsIntegrationTests.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
* @author Tobias Trelle
5454
* @author Oliver Gierke
5555
* @author Christoph Strobl
56+
* @author Minsu Kim
5657
*/
5758
@RunWith(SpringJUnit4ClassRunner.class)
5859
@ContextConfiguration("classpath:infrastructure.xml")
@@ -200,6 +201,31 @@ public void removeUnordered() {
200201
testRemove(BulkMode.UNORDERED);
201202
}
202203

204+
@Test // DATAMONGO-2218
205+
public void replaceOneOrdered() {
206+
testReplaceOne(BulkMode.ORDERED);
207+
}
208+
209+
@Test // DATAMONGO-2218
210+
public void replaceOneUnordered() {
211+
testReplaceOne(BulkMode.UNORDERED);
212+
}
213+
214+
@Test // DATAMONGO-2218
215+
public void replaceOneDoesReplace() {
216+
217+
insertSomeDocuments();
218+
219+
com.mongodb.bulk.BulkWriteResult result = createBulkOps(BulkMode.ORDERED).//
220+
replaceOne(where("_id", "1"), rawDoc("1", "value2")).//
221+
execute();
222+
223+
assertThat(result, notNullValue());
224+
assertThat(result.getMatchedCount(), is(1));
225+
assertThat(result.getModifiedCount(), is(1));
226+
assertThat(result.getInsertedCount(), is(0));
227+
}
228+
203229
/**
204230
* If working on the same set of documents, only an ordered bulk operation will yield predictable results.
205231
*/
@@ -278,6 +304,19 @@ private void testRemove(BulkMode mode) {
278304
assertThat(createBulkOps(mode).remove(removes).execute().getDeletedCount(), is(3));
279305
}
280306

307+
private void testReplaceOne(BulkMode mode) {
308+
309+
BulkOperations bulkOps = createBulkOps(mode);
310+
311+
insertSomeDocuments();
312+
313+
Query query = where("_id", "1");
314+
Document document = rawDoc("1", "value2");
315+
int modifiedCount = bulkOps.replaceOne(query, document).execute().getModifiedCount();
316+
317+
assertThat(modifiedCount, is(1));
318+
}
319+
281320
private BulkOperations createBulkOps(BulkMode mode) {
282321
return createBulkOps(mode, null);
283322
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DefaultBulkOperationsUnitTests.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.List;
2727
import java.util.Optional;
2828

29+
import com.mongodb.client.model.*;
2930
import org.bson.Document;
3031
import org.junit.Before;
3132
import org.junit.Test;
@@ -51,16 +52,13 @@
5152

5253
import com.mongodb.client.MongoCollection;
5354
import com.mongodb.client.MongoDatabase;
54-
import com.mongodb.client.model.DeleteManyModel;
55-
import com.mongodb.client.model.UpdateManyModel;
56-
import com.mongodb.client.model.UpdateOneModel;
57-
import com.mongodb.client.model.WriteModel;
5855

5956
/**
6057
* Unit tests for {@link DefaultBulkOperations}.
6158
*
6259
* @author Christoph Strobl
6360
* @author Mark Paluch
61+
* @author Minsu Kim
6462
*/
6563
@RunWith(MockitoJUnitRunner.class)
6664
public class DefaultBulkOperationsUnitTests {
@@ -133,6 +131,18 @@ public void removeShouldUseCollationWhenPresent() {
133131
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("de").build());
134132
}
135133

134+
@Test // DATAMONGO-2218
135+
public void replaceOneShouldUseCollationWhenPresent() {
136+
137+
ops.replaceOne(new BasicQuery("{}").collation(Collation.of("de")), new SomeDomainType()).execute();
138+
139+
verify(collection).bulkWrite(captor.capture(), any());
140+
141+
assertThat(captor.getValue().get(0)).isInstanceOf(ReplaceOneModel.class);
142+
assertThat(((ReplaceOneModel<Document>) captor.getValue().get(0)).getReplaceOptions().getCollation())
143+
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("de").build());
144+
}
145+
136146
@Test // DATAMONGO-1678
137147
public void bulkUpdateShouldMapQueryAndUpdateCorrectly() {
138148

@@ -156,6 +166,23 @@ public void bulkRemoveShouldMapQueryCorrectly() {
156166
assertThat(updateModel.getFilter()).isEqualTo(new Document("first_name", "danerys"));
157167
}
158168

169+
@Test // DATAMONGO-2218
170+
public void bulkReplaceOneShouldMapQueryCorrectly() {
171+
172+
SomeDomainType replacement = new SomeDomainType();
173+
replacement.firstName = "Minsu";
174+
replacement.lastName = "Kim";
175+
176+
ops.replaceOne(query(where("firstName").is("danerys")), replacement).execute();
177+
178+
verify(collection).bulkWrite(captor.capture(), any());
179+
180+
ReplaceOneModel<Document> updateModel = (ReplaceOneModel<Document>) captor.getValue().get(0);
181+
assertThat(updateModel.getFilter()).isEqualTo(new Document("first_name", "danerys"));
182+
assertThat(updateModel.getReplacement().getString("first_name")).isEqualTo("Minsu");
183+
assertThat(updateModel.getReplacement().getString("lastName")).isEqualTo("Kim");
184+
}
185+
159186
class SomeDomainType {
160187

161188
@Id String id;

0 commit comments

Comments
 (0)