Skip to content

Commit 696272a

Browse files
committed
JAVA-1134: Added BulkWriteResult.isModifiedCountAvailable(), which returns false if the server is unable to provide the count. BulkWriteResult.getModifiedCount() now throws if the count is unavailable.
1 parent 2869154 commit 696272a

9 files changed

+111
-27
lines changed

src/main/com/mongodb/AcknowledgedBulkWriteResult.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ class AcknowledgedBulkWriteResult extends BulkWriteResult {
2525
private int insertedCount;
2626
private int matchedCount;
2727
private int removedCount;
28-
private int modifiedCount;
28+
private Integer modifiedCount;
2929
private final List<BulkWriteUpsert> upserts;
3030

3131
AcknowledgedBulkWriteResult(final int insertedCount, final int matchedCount, final int removedCount,
32-
final int modifiedCount, final List<BulkWriteUpsert> upserts) {
32+
final Integer modifiedCount, final List<BulkWriteUpsert> upserts) {
3333
this.insertedCount = insertedCount;
3434
this.matchedCount = matchedCount;
3535
this.removedCount = removedCount;
@@ -41,7 +41,7 @@ class AcknowledgedBulkWriteResult extends BulkWriteResult {
4141
this(type, count, 0, upserts);
4242
}
4343

44-
AcknowledgedBulkWriteResult(final WriteRequest.Type type, final int count, final int modifiedCount,
44+
AcknowledgedBulkWriteResult(final WriteRequest.Type type, final int count, final Integer modifiedCount,
4545
final List<BulkWriteUpsert> upserts) {
4646
this(type == WriteRequest.Type.INSERT ? count : 0,
4747
(type == WriteRequest.Type.UPDATE || type == WriteRequest.Type.REPLACE) ? count : 0,
@@ -69,9 +69,20 @@ public int getRemovedCount() {
6969
return removedCount;
7070
}
7171

72+
@Override
73+
public boolean isModifiedCountAvailable() {
74+
return modifiedCount != null;
75+
}
76+
7277
@Override
7378
public int getModifiedCount() {
79+
if (modifiedCount == null) {
80+
throw new UnsupportedOperationException("The modifiedCount is not available because at least one of the servers that was " +
81+
"updated was not able to provide this information (the server is must be at least " +
82+
"version 2.6");
83+
}
7484
return modifiedCount;
85+
7586
}
7687

7788
@Override
@@ -93,13 +104,13 @@ public boolean equals(final Object o) {
93104
if (insertedCount != that.insertedCount) {
94105
return false;
95106
}
96-
if (modifiedCount != that.modifiedCount) {
107+
if (matchedCount != that.matchedCount) {
97108
return false;
98109
}
99110
if (removedCount != that.removedCount) {
100111
return false;
101112
}
102-
if (matchedCount != that.matchedCount) {
113+
if (modifiedCount != null ? !modifiedCount.equals(that.modifiedCount) : that.modifiedCount != null) {
103114
return false;
104115
}
105116
if (!upserts.equals(that.upserts)) {
@@ -111,11 +122,11 @@ public boolean equals(final Object o) {
111122

112123
@Override
113124
public int hashCode() {
114-
int result = upserts.hashCode();
115-
result = 31 * result + insertedCount;
125+
int result = insertedCount;
116126
result = 31 * result + matchedCount;
117127
result = 31 * result + removedCount;
118-
result = 31 * result + modifiedCount;
128+
result = 31 * result + (modifiedCount != null ? modifiedCount.hashCode() : 0);
129+
result = 31 * result + upserts.hashCode();
119130
return result;
120131
}
121132

src/main/com/mongodb/BulkWriteBatchCombiner.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class BulkWriteBatchCombiner {
3333
private int insertedCount;
3434
private int matchedCount;
3535
private int removedCount;
36-
private int modifiedCount;
36+
private Integer modifiedCount = 0;
3737
private final Set<BulkWriteUpsert> writeUpserts = new TreeSet<BulkWriteUpsert>(new Comparator<BulkWriteUpsert>() {
3838
@Override
3939
public int compare(final BulkWriteUpsert o1, final BulkWriteUpsert o2) {
@@ -58,7 +58,11 @@ public void addResult(final BulkWriteResult result, final IndexMap indexMap) {
5858
insertedCount += result.getInsertedCount();
5959
matchedCount += result.getMatchedCount();
6060
removedCount += result.getRemovedCount();
61-
modifiedCount += result.getModifiedCount();
61+
if (result.isModifiedCountAvailable() && modifiedCount != null) {
62+
modifiedCount += result.getModifiedCount();
63+
} else {
64+
modifiedCount = null;
65+
}
6266
mergeUpserts(result.getUpserts(), indexMap);
6367
}
6468

src/main/com/mongodb/BulkWriteResult.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,34 @@ public abstract class BulkWriteResult {
6565
*/
6666
public abstract int getRemovedCount();
6767

68+
/**
69+
* Returns true if the server was able to provide a count of modified documents. If this method returns false (which can happen if
70+
* the server is not at least version 2.6) then the {@code getModifiedCount} method will throw {@code UnsupportedOperationException}.
71+
*
72+
* @return true if modifiedCount is available
73+
*
74+
* @throws UnacknowledgedWriteException if the write was unacknowledged.
75+
* @see WriteConcern#UNACKNOWLEDGED
76+
* @see #getModifiedCount()
77+
*/
78+
public abstract boolean isModifiedCountAvailable();
79+
6880
/**
6981
* Returns the number of documents modified by updates or replacements in the write operation. This will only count documents that
7082
* were actually changed; for example, if you set the value of some field, and the field already has that value,
7183
* that will not count as a modification.
84+
* <p>
85+
* If the server is not able to provide a count of modified documents (which can happen if the server is not at least version
86+
* 2.6), then this method will throw an {@code UnsupportedOperationException}
87+
* </p>
7288
*
7389
* @return the number of documents modified by the write operation
7490
*
7591
* @throws UnacknowledgedWriteException if the write was unacknowledged.
92+
* @throws java.lang.UnsupportedOperationException if no modified count is available
7693
* @see WriteConcern#UNACKNOWLEDGED
94+
* @see #isModifiedCountAvailable()
95+
* @mongodb.server.release 2.6
7796
*/
7897
public abstract int getModifiedCount();
7998

src/main/com/mongodb/DBCollectionImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ private abstract class RunExecutor {
825825
BulkWriteResult getResult(final WriteResult writeResult) {
826826
int count = getCount(writeResult);
827827
List<BulkWriteUpsert> upsertedItems = getUpsertedItems(writeResult);
828-
int modifiedCount = (getType() == UPDATE || getType() == REPLACE) ? count - upsertedItems.size() : 0;
828+
Integer modifiedCount = (getType() == UPDATE || getType() == REPLACE) ? null : 0;
829829
return new AcknowledgedBulkWriteResult(getType(), count - upsertedItems.size(), modifiedCount, upsertedItems);
830830
}
831831

src/main/com/mongodb/UnacknowledgedBulkWriteResult.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public int getRemovedCount() {
4343
throw getUnacknowledgedWriteException();
4444
}
4545

46+
@Override
47+
public boolean isModifiedCountAvailable() {
48+
throw getUnacknowledgedWriteException();
49+
}
50+
4651
@Override
4752
public int getModifiedCount() {
4853
throw getUnacknowledgedWriteException();

src/main/com/mongodb/WriteCommandResultHelper.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import java.util.Collections;
2121
import java.util.List;
2222

23+
import static com.mongodb.WriteRequest.Type.REPLACE;
24+
import static com.mongodb.WriteRequest.Type.UPDATE;
25+
2326
final class WriteCommandResultHelper {
2427

2528
static boolean hasError(final CommandResult commandResult) {
@@ -29,7 +32,7 @@ static boolean hasError(final CommandResult commandResult) {
2932
static BulkWriteResult getBulkWriteResult(final WriteRequest.Type type, final CommandResult commandResult) {
3033
int count = getCount(commandResult);
3134
List<BulkWriteUpsert> upsertedItems = getUpsertedItems(commandResult);
32-
return new AcknowledgedBulkWriteResult(type, count - upsertedItems.size(), getModifiedCount(commandResult), upsertedItems);
35+
return new AcknowledgedBulkWriteResult(type, count - upsertedItems.size(), getModifiedCount(type, commandResult), upsertedItems);
3336
}
3437

3538
static BulkWriteException getBulkWriteException(final WriteRequest.Type type, final CommandResult commandResult) {
@@ -84,8 +87,12 @@ private static int getCount(final CommandResult commandResult) {
8487
return commandResult.getInt("n");
8588
}
8689

87-
private static Integer getModifiedCount(final CommandResult commandResult) {
88-
return commandResult.getInt("nModified", 0);
90+
private static Integer getModifiedCount(final WriteRequest.Type type, final CommandResult commandResult) {
91+
Integer modifiedCount = (Integer) commandResult.get("nModified");
92+
if (modifiedCount == null && !(type == UPDATE || type == REPLACE)) {
93+
modifiedCount = 0;
94+
}
95+
return modifiedCount;
8996
}
9097

9198
private static DBObject getErrInfo(final DBObject response) {

src/test/com/mongodb/BulkWriteBatchCombinerSpecification.groovy

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ class BulkWriteBatchCombinerSpecification extends Specification {
4848
result == new AcknowledgedBulkWriteResult(INSERT, 1, 0, [])
4949
}
5050

51+
def 'should handle null modifiedCount'() {
52+
def runResults = new BulkWriteBatchCombiner(new ServerAddress(), ACKNOWLEDGED)
53+
runResults.addResult(new AcknowledgedBulkWriteResult(UPDATE, 1, null, []), new IndexMap.RangeBased().add(0, 0))
54+
runResults.addResult(new AcknowledgedBulkWriteResult(INSERT, 1, 0, []), new IndexMap.RangeBased().add(0, 0))
55+
56+
when:
57+
def result = runResults.getResult()
58+
59+
then:
60+
result == new AcknowledgedBulkWriteResult(1, 1, 0, null, [])
61+
}
62+
5163
def 'should sort upserts'() {
5264
given:
5365
def runResults = new BulkWriteBatchCombiner(new ServerAddress(), ACKNOWLEDGED)

src/test/com/mongodb/BulkWriteOperationSpecification.groovy

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,14 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
175175
def result = operation.execute()
176176

177177
then:
178-
result == new AcknowledgedBulkWriteResult(UPDATE, 1, 1, [])
178+
result == new AcknowledgedBulkWriteResult(UPDATE, 1, expectedModifiedCount(1), [])
179179
collection.find(new BasicDBObject('y', 1), new BasicDBObject('x', 1).append('_id', 0)).toArray() == [new BasicDBObject('x', true)]
180180

181181
where:
182182
ordered << [true, false]
183183
}
184184

185-
def 'when documents match the query, an update should update all of them'() {
185+
def 'when documents match the query, an update should update all of them'() {
186186
given:
187187
collection.insert(new BasicDBObject('x', true))
188188
collection.insert(new BasicDBObject('x', true))
@@ -195,7 +195,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
195195
def result = operation.execute()
196196

197197
then:
198-
result == new AcknowledgedBulkWriteResult(UPDATE, 2, 2, [])
198+
result == new AcknowledgedBulkWriteResult(UPDATE, 2, expectedModifiedCount(2), [])
199199
collection.count(new BasicDBObject('y', 1)) == 2
200200

201201
where:
@@ -212,7 +212,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
212212
def result = operation.execute()
213213

214214
then:
215-
result == new AcknowledgedBulkWriteResult(UPDATE, 0, [new BulkWriteUpsert(0, id)])
215+
result == new AcknowledgedBulkWriteResult(UPDATE, 0, expectedModifiedCount(0), [new BulkWriteUpsert(0, id)])
216216
collection.findOne() == new BasicDBObject('_id', id).append('x', 2)
217217

218218
where:
@@ -229,7 +229,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
229229
def result = operation.execute()
230230

231231
then:
232-
result == new AcknowledgedBulkWriteResult(UPDATE, 0, [new BulkWriteUpsert(0, id)])
232+
result == new AcknowledgedBulkWriteResult(UPDATE, 0, expectedModifiedCount(0), [new BulkWriteUpsert(0, id)])
233233
collection.findOne() == new BasicDBObject('_id', id).append('x', 2)
234234

235235
where:
@@ -249,7 +249,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
249249
def result = operation.execute()
250250

251251
then:
252-
result == new AcknowledgedBulkWriteResult(UPDATE, 2, 2, [])
252+
result == new AcknowledgedBulkWriteResult(UPDATE, 2, expectedModifiedCount(2), [])
253253
collection.count(new BasicDBObject('y', 1)) == 2
254254

255255
where:
@@ -284,7 +284,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
284284
def result = operation.execute()
285285

286286
then:
287-
result == new AcknowledgedBulkWriteResult(UPDATE, 0, [new BulkWriteUpsert(0, id)])
287+
result == new AcknowledgedBulkWriteResult(UPDATE, 0, expectedModifiedCount(0), [new BulkWriteUpsert(0, id)])
288288
collection.findOne() == new BasicDBObject('_id', id).append('x', 2)
289289

290290
where:
@@ -304,7 +304,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
304304
def result = operation.execute()
305305

306306
then:
307-
result == new AcknowledgedBulkWriteResult(UPDATE, 1, 1, [])
307+
result == new AcknowledgedBulkWriteResult(UPDATE, 1, expectedModifiedCount(1), [])
308308
collection.find(new BasicDBObject('x', false), new BasicDBObject('_id', 0)).toArray() == [replacement]
309309

310310
where:
@@ -322,7 +322,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
322322
def result = operation.execute()
323323

324324
then:
325-
result == new AcknowledgedBulkWriteResult(UPDATE, 1, 1, [])
325+
result == new AcknowledgedBulkWriteResult(UPDATE, 1, expectedModifiedCount(1), [])
326326
collection.findOne() == new BasicDBObject('_id', id).append('x', 2)
327327

328328
where:
@@ -340,7 +340,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
340340
def result = operation.execute()
341341

342342
then:
343-
result == new AcknowledgedBulkWriteResult(REPLACE, 1, 1, [])
343+
result == new AcknowledgedBulkWriteResult(REPLACE, 1, expectedModifiedCount(1), [])
344344
collection.findOne() == new BasicDBObject('_id', 1).append('x', 2)
345345

346346
where:
@@ -359,7 +359,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
359359
def result = operation.execute()
360360

361361
then:
362-
result == new AcknowledgedBulkWriteResult(REPLACE, 1, 1, [])
362+
result == new AcknowledgedBulkWriteResult(REPLACE, 1, expectedModifiedCount(1), [])
363363
collection.count() == 1
364364
}
365365

@@ -374,7 +374,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
374374
def result = operation.execute()
375375

376376
then:
377-
result == new AcknowledgedBulkWriteResult(2, 4, 2, 4, [])
377+
result == new AcknowledgedBulkWriteResult(2, 4, 2, expectedModifiedCount(4), [])
378378

379379
collection.findOne(new BasicDBObject('_id', 1)) == new BasicDBObject('_id', 1).append('x', 2)
380380
collection.findOne(new BasicDBObject('_id', 2)) == new BasicDBObject('_id', 2).append('x', 3)
@@ -446,7 +446,7 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
446446
def result = operation.execute()
447447

448448
then:
449-
result == new AcknowledgedBulkWriteResult(2, 4, 2, 4, [])
449+
result == new AcknowledgedBulkWriteResult(2, 4, 2, expectedModifiedCount(4), [])
450450

451451
collection.findOne(new BasicDBObject('_id', 1)) == new BasicDBObject('_id', 1).append('x', 2)
452452
collection.findOne(new BasicDBObject('_id', 2)) == new BasicDBObject('_id', 2).append('x', 3)
@@ -712,4 +712,8 @@ class BulkWriteOperationSpecification extends FunctionalSpecification {
712712
private BulkWriteOperation initializeBulkOperation(boolean ordered) {
713713
ordered ? collection.initializeOrderedBulkOperation() : collection.initializeUnorderedBulkOperation()
714714
}
715+
716+
private static Integer expectedModifiedCount(final int expectedCountForServersThatSupportIt) {
717+
(serverIsAtLeastVersion(2.5)) ? expectedCountForServersThatSupportIt : null
718+
}
715719
}

src/test/com/mongodb/WriteCommandHelperSpecification.groovy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import static com.mongodb.WriteCommandResultHelper.getBulkWriteException
2222
import static com.mongodb.WriteCommandResultHelper.getBulkWriteResult
2323
import static com.mongodb.WriteCommandResultHelper.hasError
2424
import static com.mongodb.WriteRequest.Type.INSERT
25+
import static com.mongodb.WriteRequest.Type.REMOVE
26+
import static com.mongodb.WriteRequest.Type.REPLACE
2527
import static com.mongodb.WriteRequest.Type.UPDATE
2628

2729
class WriteCommandHelperSpecification extends Specification {
@@ -41,6 +43,26 @@ class WriteCommandHelperSpecification extends Specification {
4143
.getUpserts()
4244
}
4345

46+
def 'should not have modified count for update with no nModified field in the result'() {
47+
expect:
48+
!getBulkWriteResult(UPDATE, getCommandResult(new BasicDBObject('n', 1))).isModifiedCountAvailable()
49+
}
50+
51+
def 'should not have modified count for replace with no nModified field in the result'() {
52+
expect:
53+
!getBulkWriteResult(REPLACE, getCommandResult(new BasicDBObject('n', 1))).isModifiedCountAvailable()
54+
}
55+
56+
def 'should have modified count of 0 for insert with no nModified field in the result'() {
57+
expect:
58+
0 == getBulkWriteResult(INSERT, getCommandResult(new BasicDBObject('n', 1))).getModifiedCount()
59+
}
60+
61+
def 'should have modified count of 0 for remove with no nModified field in the result'() {
62+
expect:
63+
0 == getBulkWriteResult(REMOVE, getCommandResult(new BasicDBObject('n', 1))).getModifiedCount()
64+
}
65+
4466
def 'should not have error if writeErrors is empty and writeConcernError is missing'() {
4567
expect:
4668
!hasError(getCommandResult(new BasicDBObject()));

0 commit comments

Comments
 (0)