diff --git a/driver-core/src/main/com/mongodb/client/model/ReplaceOptions.java b/driver-core/src/main/com/mongodb/client/model/ReplaceOptions.java
index 249a828364a..7a26e0997ba 100644
--- a/driver-core/src/main/com/mongodb/client/model/ReplaceOptions.java
+++ b/driver-core/src/main/com/mongodb/client/model/ReplaceOptions.java
@@ -37,6 +37,7 @@ public class ReplaceOptions {
private String hintString;
private BsonValue comment;
private Bson variables;
+ private Bson sort;
/**
* Returns true if a new document should be inserted if there are no matches to the query filter. The default is false.
@@ -221,6 +222,43 @@ public ReplaceOptions let(final Bson variables) {
return this;
}
+ /**
+ * Gets the sort criteria to apply to the operation.
+ *
+ *
+ * The sort criteria determines which document the operation replaces if the query matches multiple documents.
+ * The first document matched by the sort criteria will be replaced.
+ * The default is null, which means no specific sort criteria is applied.
+ *
+ * @return a document describing the sort criteria, or null if no sort is specified.
+ * @mongodb.driver.manual reference/method/db.collection.replaceOne/ Sort
+ * @mongodb.server.release 8.0
+ * @since 5.3
+ * @see #sort(Bson)
+ */
+ @Nullable
+ public Bson getSort() {
+ return sort;
+ }
+
+ /**
+ * Sets the sort criteria to apply to the operation. A null value means no sort criteria is set.
+ *
+ *
+ * The sort criteria determines which document the operation replaces if the query matches multiple documents.
+ * The first document matched by the specified sort criteria will be replaced.
+ *
+ * @param sort the sort criteria, which may be null.
+ * @return this
+ * @mongodb.driver.manual reference/method/db.collection.replaceOne/ Sort
+ * @mongodb.server.release 8.0
+ * @since 5.3
+ */
+ public ReplaceOptions sort(@Nullable final Bson sort) {
+ this.sort = sort;
+ return this;
+ }
+
@Override
public String toString() {
return "ReplaceOptions{"
@@ -231,6 +269,7 @@ public String toString() {
+ ", hintString=" + hintString
+ ", comment=" + comment
+ ", let=" + variables
+ + ", sort=" + sort
+ '}';
}
}
diff --git a/driver-core/src/main/com/mongodb/client/model/UpdateOptions.java b/driver-core/src/main/com/mongodb/client/model/UpdateOptions.java
index d290610c816..88eb3cb6acb 100644
--- a/driver-core/src/main/com/mongodb/client/model/UpdateOptions.java
+++ b/driver-core/src/main/com/mongodb/client/model/UpdateOptions.java
@@ -40,6 +40,7 @@ public class UpdateOptions {
private String hintString;
private BsonValue comment;
private Bson variables;
+ private Bson sort;
/**
* Returns true if a new document should be inserted if there are no matches to the query filter. The default is false.
@@ -256,6 +257,43 @@ public UpdateOptions let(final Bson variables) {
return this;
}
+ /**
+ * Gets the sort criteria to apply to the operation.
+ *
+ *
+ * The sort criteria determines which document the operation updates if the query matches multiple documents.
+ * The first document matched by the sort criteria will be updated.
+ * The default is null, which means no specific sort criteria is applied.
+ *
+ * @return a document describing the sort criteria, or null if no sort is specified.
+ * @mongodb.driver.manual reference/method/db.collection.updateOne/ Sort
+ * @mongodb.server.release 8.0
+ * @since 5.3
+ * @see #sort(Bson)
+ */
+ @Nullable
+ public Bson getSort() {
+ return sort;
+ }
+
+ /**
+ * Sets the sort criteria to apply to the operation. A null value means no sort criteria is set.
+ *
+ *
+ * The sort criteria determines which document the operation updates if the query matches multiple documents.
+ * The first document matched by the specified sort criteria will be updated.
+ *
+ * @param sort the sort criteria, which may be null.
+ * @return this
+ * @mongodb.driver.manual reference/method/db.collection.updateOne/ Sort
+ * @mongodb.server.release 8.0
+ * @since 5.3
+ */
+ public UpdateOptions sort(@Nullable final Bson sort) {
+ this.sort = sort;
+ return this;
+ }
+
@Override
public String toString() {
return "UpdateOptions{"
@@ -267,6 +305,7 @@ public String toString() {
+ ", hintString=" + hintString
+ ", comment=" + comment
+ ", let=" + variables
+ + ", sort=" + sort
+ '}';
}
}
diff --git a/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java b/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java
index 5a7df089641..e9d0b13c3cd 100644
--- a/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java
+++ b/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java
@@ -40,6 +40,7 @@ public final class UpdateRequest extends WriteRequest {
private List arrayFilters;
@Nullable private BsonDocument hint;
@Nullable private String hintString;
+ @Nullable private BsonDocument sort;
public UpdateRequest(final BsonDocument filter, @Nullable final BsonValue update, final Type updateType) {
if (updateType != Type.UPDATE && updateType != Type.REPLACE) {
@@ -128,5 +129,15 @@ public UpdateRequest hintString(@Nullable final String hint) {
this.hintString = hint;
return this;
}
+
+ @Nullable
+ public BsonDocument getSort() {
+ return sort;
+ }
+
+ public UpdateRequest sort(@Nullable final BsonDocument sort) {
+ this.sort = sort;
+ return this;
+ }
}
diff --git a/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java b/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java
index d628a39238d..55bbac03b8b 100644
--- a/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java
+++ b/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java
@@ -270,6 +270,11 @@ public void encode(final BsonWriter writer, final WriteRequestWithIndex writeReq
} else if (update.getHintString() != null) {
writer.writeString("hint", update.getHintString());
}
+ if (update.getSort() != null) {
+ writer.writeName("sort");
+ getCodec(assertNotNull(update.getSort())).encode(writer, assertNotNull(update.getSort()),
+ EncoderContext.builder().build());
+ }
writer.writeEndDocument();
} else {
DeleteRequest deleteRequest = (DeleteRequest) writeRequestWithIndex.getWriteRequest();
diff --git a/driver-core/src/main/com/mongodb/internal/operation/Operations.java b/driver-core/src/main/com/mongodb/internal/operation/Operations.java
index d00c5a446c9..ecdd215ba91 100644
--- a/driver-core/src/main/com/mongodb/internal/operation/Operations.java
+++ b/driver-core/src/main/com/mongodb/internal/operation/Operations.java
@@ -464,7 +464,8 @@ MixedBulkWriteOperation bulkWrite(final List extends WriteModel extends TDoc
.upsert(replaceOneModel.getReplaceOptions().isUpsert())
.collation(replaceOneModel.getReplaceOptions().getCollation())
.hint(toBsonDocument(replaceOneModel.getReplaceOptions().getHint()))
- .hintString(replaceOneModel.getReplaceOptions().getHintString());
+ .hintString(replaceOneModel.getReplaceOptions().getHintString())
+ .sort(toBsonDocument(replaceOneModel.getReplaceOptions().getSort()));
} else if (writeModel instanceof UpdateOneModel) {
UpdateOneModel updateOneModel = (UpdateOneModel) writeModel;
BsonValue update = updateOneModel.getUpdate() != null ? toBsonDocument(updateOneModel.getUpdate())
@@ -475,7 +476,8 @@ MixedBulkWriteOperation bulkWrite(final List extends WriteModel extends TDoc
.collation(updateOneModel.getOptions().getCollation())
.arrayFilters(toBsonDocumentList(updateOneModel.getOptions().getArrayFilters()))
.hint(toBsonDocument(updateOneModel.getOptions().getHint()))
- .hintString(updateOneModel.getOptions().getHintString());
+ .hintString(updateOneModel.getOptions().getHintString())
+ .sort(toBsonDocument(updateOneModel.getOptions().getSort()));
} else if (writeModel instanceof UpdateManyModel) {
UpdateManyModel updateManyModel = (UpdateManyModel) writeModel;
BsonValue update = updateManyModel.getUpdate() != null ? toBsonDocument(updateManyModel.getUpdate())
diff --git a/driver-core/src/test/unit/com/mongodb/client/model/UpdateOptionsSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/UpdateOptionsSpecification.groovy
index 0481120b05a..cd588936c18 100644
--- a/driver-core/src/test/unit/com/mongodb/client/model/UpdateOptionsSpecification.groovy
+++ b/driver-core/src/test/unit/com/mongodb/client/model/UpdateOptionsSpecification.groovy
@@ -78,4 +78,12 @@ class UpdateOptionsSpecification extends Specification {
where:
hint << [null, '_id_']
}
+
+ def 'should set sort'() {
+ expect:
+ new UpdateOptions().sort(sort).getSort() == sort
+
+ where:
+ sort << [null, new BsonDocument('_id', new BsonInt32(1))]
+ }
}
diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/UpdateRequestSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/operation/UpdateRequestSpecification.groovy
index f56411578cf..7ab84bb670b 100644
--- a/driver-core/src/test/unit/com/mongodb/internal/operation/UpdateRequestSpecification.groovy
+++ b/driver-core/src/test/unit/com/mongodb/internal/operation/UpdateRequestSpecification.groovy
@@ -125,4 +125,13 @@ class UpdateRequestSpecification extends Specification {
where:
arrayFilters << [null, [], [new BsonDocument('a.b', new BsonInt32(42))]]
}
+
+ def 'should set sort property'() {
+ expect:
+ new UpdateRequest(new BsonDocument(), new BsonDocument(), type).sort(sort).getSort() == sort
+
+ where:
+ type << [WriteRequest.Type.UPDATE, WriteRequest.Type.REPLACE]
+ sort << [null, new BsonDocument('_id', new BsonInt32(1))]
+ }
}
diff --git a/driver-legacy/src/main/com/mongodb/ReplaceRequest.java b/driver-legacy/src/main/com/mongodb/ReplaceRequest.java
index 8427471af18..09443f1ee4d 100644
--- a/driver-legacy/src/main/com/mongodb/ReplaceRequest.java
+++ b/driver-legacy/src/main/com/mongodb/ReplaceRequest.java
@@ -60,7 +60,7 @@ com.mongodb.internal.bulk.WriteRequest toNew(final DBCollection dbCollection) {
return new UpdateRequest(new BsonDocumentWrapper<>(query, codec),
new BsonDocumentWrapper<>(document, replacementCodec),
com.mongodb.internal.bulk.WriteRequest.Type.REPLACE)
- .upsert(isUpsert())
- .collation(getCollation());
+ .upsert(isUpsert())
+ .collation(getCollation());
}
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
index 64cf204e565..192bde29e5e 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
@@ -1159,6 +1159,9 @@ private UpdateOptions getUpdateOptions(final BsonDocument arguments) {
case "collation":
options.collation(asCollation(cur.getValue().asDocument()));
break;
+ case "sort":
+ options.sort(cur.getValue().asDocument());
+ break;
default:
throw new UnsupportedOperationException("Unsupported argument: " + cur.getKey());
}
@@ -1193,6 +1196,9 @@ private ReplaceOptions getReplaceOptions(final BsonDocument arguments) {
case "collation":
options.collation(asCollation(cur.getValue().asDocument()));
break;
+ case "sort":
+ options.sort(cur.getValue().asDocument());
+ break;
default:
throw new UnsupportedOperationException("Unsupported argument: " + cur.getKey());
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java
index 92a64024e92..0b2f4a6a2d5 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java
@@ -135,15 +135,6 @@ public static void doSkips(final TestDef def) {
.test("crud", "findOneAndUpdate-hint-unacknowledged", "Unacknowledged findOneAndUpdate with hint document on 4.4+ server")
.test("crud", "findOneAndDelete-hint-unacknowledged", "Unacknowledged findOneAndDelete with hint string on 4.4+ server")
.test("crud", "findOneAndDelete-hint-unacknowledged", "Unacknowledged findOneAndDelete with hint document on 4.4+ server");
- def.skipJira("https://jira.mongodb.org/browse/JAVA-5622")
- .test("crud", "updateOne-sort", "UpdateOne with sort option")
- .test("crud", "updateOne-sort", "updateOne with sort option unsupported (server-side error)")
- .test("crud", "replaceOne-sort", "ReplaceOne with sort option")
- .test("crud", "replaceOne-sort", "replaceOne with sort option unsupported (server-side error)")
- .test("crud", "BulkWrite updateOne-sort", "BulkWrite updateOne with sort option")
- .test("crud", "BulkWrite updateOne-sort", "BulkWrite updateOne with sort option unsupported (server-side error)")
- .test("crud", "BulkWrite replaceOne-sort", "BulkWrite replaceOne with sort option")
- .test("crud", "BulkWrite replaceOne-sort", "BulkWrite replaceOne with sort option unsupported (server-side error)");
// gridfs
diff --git a/driver-sync/src/test/unit/com/mongodb/client/internal/MongoCollectionSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/internal/MongoCollectionSpecification.groovy
index 2fba3b90a0a..cbe43c10517 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/internal/MongoCollectionSpecification.groovy
+++ b/driver-sync/src/test/unit/com/mongodb/client/internal/MongoCollectionSpecification.groovy
@@ -813,7 +813,7 @@ class MongoCollectionSpecification extends Specification {
def expectedOperation = { boolean upsert, WriteConcern wc, Boolean bypassValidation, Collation collation ->
new MixedBulkWriteOperation(namespace,
[new UpdateRequest(new BsonDocument('a', new BsonInt32(1)), new BsonDocument('a', new BsonInt32(10)), REPLACE)
- .collation(collation).upsert(upsert).hint(hint).hintString(hintString)], true, wc, retryWrites)
+ .collation(collation).upsert(upsert).hint(hint).hintString(hintString).sort(sort)], true, wc, retryWrites)
.bypassDocumentValidation(bypassValidation)
}
def replaceOneMethod = collection.&replaceOne
@@ -821,7 +821,7 @@ class MongoCollectionSpecification extends Specification {
when:
def result = execute(replaceOneMethod, session, new Document('a', 1), new Document('a', 10),
new ReplaceOptions().upsert(true).bypassDocumentValidation(bypassDocumentValidation).collation(collation)
- .hint(hint).hintString(hintString))
+ .hint(hint).hintString(hintString).sort(sort))
executor.getClientSession() == session
def operation = executor.getWriteOperation() as MixedBulkWriteOperation
@@ -830,7 +830,7 @@ class MongoCollectionSpecification extends Specification {
result == expectedResult
where:
- [bypassDocumentValidation, modifiedCount, upsertedId, writeConcern, session, retryWrites, hint, hintString] << [
+ [bypassDocumentValidation, modifiedCount, upsertedId, writeConcern, session, retryWrites, hint, hintString, sort] << [
[null, true, false],
[1],
[null, new BsonInt32(42)],
@@ -838,7 +838,8 @@ class MongoCollectionSpecification extends Specification {
[null, Stub(ClientSession)],
[true, false],
[null, new BsonDocument('_id', new BsonInt32(1))],
- [null, '_id_']
+ [null, '_id_'],
+ [null, new BsonDocument('_id', new BsonInt32(1))]
].combinations()
}
@@ -880,11 +881,11 @@ class MongoCollectionSpecification extends Specification {
def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, writeConcern,
retryWrites, true, readConcern, JAVA_LEGACY, null, TIMEOUT_SETTINGS, executor)
def expectedOperation = { boolean upsert, WriteConcern wc, Boolean bypassDocumentValidation, Collation collation,
- List filters, BsonDocument hintDoc, String hintStr ->
+ List filters, BsonDocument hintDoc, String hintStr, BsonDocument sortDoc ->
new MixedBulkWriteOperation(namespace,
[new UpdateRequest(new BsonDocument('a', new BsonInt32(1)), new BsonDocument('a', new BsonInt32(10)), UPDATE)
.multi(false).upsert(upsert).collation(collation).arrayFilters(filters)
- .hint(hintDoc).hintString(hintStr)], true, wc, retryWrites)
+ .hint(hintDoc).hintString(hintStr).sort(sortDoc)], true, wc, retryWrites)
.bypassDocumentValidation(bypassDocumentValidation)
}
def updateOneMethod = collection.&updateOne
@@ -894,29 +895,30 @@ class MongoCollectionSpecification extends Specification {
def operation = executor.getWriteOperation() as MixedBulkWriteOperation
then:
- expect operation, isTheSameAs(expectedOperation(false, writeConcern, null, null, null, null, null))
+ expect operation, isTheSameAs(expectedOperation(false, writeConcern, null, null, null, null, null, null))
executor.getClientSession() == session
result == expectedResult
when:
result = execute(updateOneMethod, session, new Document('a', 1), new Document('a', 10),
new UpdateOptions().upsert(true).bypassDocumentValidation(true).collation(collation)
- .arrayFilters(arrayFilters).hint(hint).hintString(hintString))
+ .arrayFilters(arrayFilters).hint(hint).hintString(hintString).sort(sort))
operation = executor.getWriteOperation() as MixedBulkWriteOperation
then:
- expect operation, isTheSameAs(expectedOperation(true, writeConcern, true, collation, arrayFilters, hint, hintString))
+ expect operation, isTheSameAs(expectedOperation(true, writeConcern, true, collation, arrayFilters, hint, hintString, sort))
executor.getClientSession() == session
result == expectedResult
where:
- [writeConcern, arrayFilters, session, retryWrites, hint, hintString] << [
+ [writeConcern, arrayFilters, session, retryWrites, hint, hintString, sort] << [
[ACKNOWLEDGED, UNACKNOWLEDGED],
[null, [], [new BsonDocument('a.b', new BsonInt32(42))]],
[null, Stub(ClientSession)],
[true, false],
[null, new BsonDocument('_id', new BsonInt32(1))],
- [null, '_id_']
+ [null, '_id_'],
+ [null, new BsonDocument('_id', new BsonInt32(1))]
].combinations()
}