diff --git a/driver-core/src/main/com/mongodb/client/model/bulk/ClientReplaceOneOptions.java b/driver-core/src/main/com/mongodb/client/model/bulk/ClientReplaceOneOptions.java
index 2142d736f60..4de01a94843 100644
--- a/driver-core/src/main/com/mongodb/client/model/bulk/ClientReplaceOneOptions.java
+++ b/driver-core/src/main/com/mongodb/client/model/bulk/ClientReplaceOneOptions.java
@@ -74,4 +74,19 @@ static ClientReplaceOneOptions clientReplaceOneOptions() {
*/
@Override
ClientReplaceOneOptions upsert(@Nullable Boolean upsert);
+
+ /**
+ * 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. {@code null} represents the server default.
+ * @return this
+ * @mongodb.driver.manual reference/method/db.collection.replaceOne/ Sort
+ * @mongodb.server.release 8.0
+ * @since 5.4
+ */
+ ClientReplaceOneOptions sort(@Nullable Bson sort);
}
diff --git a/driver-core/src/main/com/mongodb/client/model/bulk/ClientUpdateOneOptions.java b/driver-core/src/main/com/mongodb/client/model/bulk/ClientUpdateOneOptions.java
index 9b04ec6ef15..c5abea43b2a 100644
--- a/driver-core/src/main/com/mongodb/client/model/bulk/ClientUpdateOneOptions.java
+++ b/driver-core/src/main/com/mongodb/client/model/bulk/ClientUpdateOneOptions.java
@@ -85,4 +85,19 @@ static ClientUpdateOneOptions clientUpdateOneOptions() {
*/
@Override
ClientUpdateOneOptions upsert(@Nullable Boolean upsert);
+
+ /**
+ * 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. {@code null} represents the server default.
+ * @return this
+ * @mongodb.driver.manual reference/method/db.collection.updateOne/ Sort
+ * @mongodb.server.release 8.0
+ * @since 5.4
+ */
+ ClientUpdateOneOptions sort(@Nullable Bson sort);
}
diff --git a/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientReplaceOneOptions.java b/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientReplaceOneOptions.java
index 18e9d060763..f7172488bfc 100644
--- a/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientReplaceOneOptions.java
+++ b/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientReplaceOneOptions.java
@@ -38,6 +38,8 @@ public final class ConcreteClientReplaceOneOptions implements ClientReplaceOneOp
private String hintString;
@Nullable
private Boolean upsert;
+ @Nullable
+ private Bson sort;
public ConcreteClientReplaceOneOptions() {
}
@@ -89,6 +91,21 @@ public ClientReplaceOneOptions upsert(@Nullable final Boolean upsert) {
return this;
}
+ /**
+ * @see ClientReplaceOneOptions#sort(Bson)
+ */
+ public ClientReplaceOneOptions sort(final Bson sort) {
+ this.sort = sort;
+ return this;
+ }
+
+ /**
+ * @see ClientReplaceOneOptions#sort(Bson)
+ */
+ public Optional getSort() {
+ return ofNullable(sort);
+ }
+
/**
* @see #upsert(Boolean)
*/
@@ -103,6 +120,7 @@ public String toString() {
+ ", hint=" + hint
+ ", hintString='" + hintString + '\''
+ ", upsert=" + upsert
+ + ", sort=" + sort
+ '}';
}
}
diff --git a/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientUpdateOneOptions.java b/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientUpdateOneOptions.java
index fdf960ed1df..3bd5f1451d7 100644
--- a/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientUpdateOneOptions.java
+++ b/driver-core/src/main/com/mongodb/internal/client/model/bulk/ConcreteClientUpdateOneOptions.java
@@ -20,12 +20,19 @@
import com.mongodb.lang.Nullable;
import org.bson.conversions.Bson;
+import java.util.Optional;
+
+import static java.util.Optional.ofNullable;
+
/**
* This class is not part of the public API and may be removed or changed at any time.
*/
public final class ConcreteClientUpdateOneOptions extends AbstractClientUpdateOptions implements ClientUpdateOneOptions {
static final ConcreteClientUpdateOneOptions MUTABLE_EMPTY = new ConcreteClientUpdateOneOptions();
+ @Nullable
+ private Bson sort;
+
public ConcreteClientUpdateOneOptions() {
}
@@ -54,6 +61,21 @@ public ConcreteClientUpdateOneOptions upsert(@Nullable final Boolean upsert) {
return (ConcreteClientUpdateOneOptions) super.upsert(upsert);
}
+ /**
+ * @see ClientUpdateOneOptions#sort(Bson)
+ */
+ public ConcreteClientUpdateOneOptions sort(final Bson sort) {
+ this.sort = sort;
+ return this;
+ }
+
+ /**
+ * @see ClientUpdateOneOptions#sort(Bson)
+ */
+ public Optional getSort() {
+ return ofNullable(sort);
+ }
+
@Override
public String toString() {
return "ClientUpdateOneOptions{"
@@ -62,6 +84,7 @@ public String toString() {
+ ", hint=" + getHint().orElse(null)
+ ", hintString=" + getHintString().map(s -> '\'' + s + '\'') .orElse(null)
+ ", upsert=" + isUpsert().orElse(null)
+ + ", sort=" + getSort().orElse(null)
+ '}';
}
}
diff --git a/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java b/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java
index 880e1db8521..aa8973ec092 100644
--- a/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java
+++ b/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java
@@ -93,6 +93,7 @@ public ClusterableServer create(final Cluster cluster, final ServerAddress serve
new InternalStreamConnectionFactory(clusterMode, true, heartbeatStreamFactory, null, applicationName,
mongoDriverInformation, emptyList(), loggerSettings, null, serverApi),
clusterMode, serverApi, isFunctionAsAServiceEnvironment, sdamProvider, heartbeatOperationContextFactory);
+
ConnectionPool connectionPool = new DefaultConnectionPool(serverId,
new InternalStreamConnectionFactory(clusterMode, streamFactory, credential, applicationName,
mongoDriverInformation, compressorList, loggerSettings, commandListener, serverApi),
diff --git a/driver-core/src/main/com/mongodb/internal/operation/ClientBulkWriteOperation.java b/driver-core/src/main/com/mongodb/internal/operation/ClientBulkWriteOperation.java
index ccd7f272e95..f6ff7632c8f 100644
--- a/driver-core/src/main/com/mongodb/internal/operation/ClientBulkWriteOperation.java
+++ b/driver-core/src/main/com/mongodb/internal/operation/ClientBulkWriteOperation.java
@@ -1247,6 +1247,14 @@ private void encodeWriteModelInternals(
});
}
+ private void encodeWriteModelInternals(final BsonWriter writer, final ConcreteClientUpdateOneModel model) {
+ encodeWriteModelInternals(writer, (AbstractClientUpdateModel>) model);
+ model.getOptions().getSort().ifPresent(value -> {
+ writer.writeName("sort");
+ encodeUsingRegistry(writer, value);
+ });
+ }
+
private void encodeWriteModelInternals(final BsonWriter writer, final AbstractClientUpdateModel> model) {
writer.writeName("filter");
encodeUsingRegistry(writer, model.getFilter());
@@ -1294,6 +1302,10 @@ private void encodeWriteModelInternals(final BsonBinaryWriter writer, final Conc
});
options.getHintString().ifPresent(value -> writer.writeString("hint", value));
options.isUpsert().ifPresent(value -> writer.writeBoolean("upsert", value));
+ options.getSort().ifPresent(value -> {
+ writer.writeName("sort");
+ encodeUsingRegistry(writer, value);
+ });
}
private void encodeWriteModelInternals(final BsonWriter writer, final AbstractClientDeleteModel> model) {
diff --git a/driver-core/src/test/resources/unified-test-format/crud/client-bulkWrite-replaceOne-sort.json b/driver-core/src/test/resources/unified-test-format/crud/client-bulkWrite-replaceOne-sort.json
new file mode 100644
index 00000000000..b86bc5f9429
--- /dev/null
+++ b/driver-core/src/test/resources/unified-test-format/crud/client-bulkWrite-replaceOne-sort.json
@@ -0,0 +1,163 @@
+{
+ "description": "client bulkWrite updateOne-sort",
+ "schemaVersion": "1.4",
+ "runOnRequirements": [
+ {
+ "minServerVersion": "8.0",
+ "serverless": "forbid"
+ }
+ ],
+ "createEntities": [
+ {
+ "client": {
+ "id": "client0",
+ "observeEvents": [
+ "commandStartedEvent",
+ "commandSucceededEvent"
+ ]
+ }
+ },
+ {
+ "database": {
+ "id": "database0",
+ "client": "client0",
+ "databaseName": "crud-tests"
+ }
+ },
+ {
+ "collection": {
+ "id": "collection0",
+ "database": "database0",
+ "collectionName": "coll0"
+ }
+ }
+ ],
+ "initialData": [
+ {
+ "collectionName": "coll0",
+ "databaseName": "crud-tests",
+ "documents": [
+ {
+ "_id": 1,
+ "x": 11
+ },
+ {
+ "_id": 2,
+ "x": 22
+ },
+ {
+ "_id": 3,
+ "x": 33
+ }
+ ]
+ }
+ ],
+ "_yamlAnchors": {
+ "namespace": "crud-tests.coll0"
+ },
+ "tests": [
+ {
+ "description": "client bulkWrite replaceOne with sort option",
+ "operations": [
+ {
+ "object": "client0",
+ "name": "clientBulkWrite",
+ "arguments": {
+ "models": [
+ {
+ "replaceOne": {
+ "namespace": "crud-tests.coll0",
+ "filter": {
+ "_id": {
+ "$gt": 1
+ }
+ },
+ "sort": {
+ "_id": -1
+ },
+ "replacement": {
+ "x": 1
+ }
+ }
+ }
+ ]
+ }
+ }
+ ],
+ "expectEvents": [
+ {
+ "client": "client0",
+ "events": [
+ {
+ "commandStartedEvent": {
+ "commandName": "bulkWrite",
+ "databaseName": "admin",
+ "command": {
+ "bulkWrite": 1,
+ "ops": [
+ {
+ "update": 0,
+ "filter": {
+ "_id": {
+ "$gt": 1
+ }
+ },
+ "updateMods": {
+ "x": 1
+ },
+ "sort": {
+ "_id": -1
+ },
+ "multi": {
+ "$$unsetOrMatches": false
+ },
+ "upsert": {
+ "$$unsetOrMatches": false
+ }
+ }
+ ],
+ "nsInfo": [
+ {
+ "ns": "crud-tests.coll0"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "commandSucceededEvent": {
+ "reply": {
+ "ok": 1,
+ "nErrors": 0,
+ "nMatched": 1,
+ "nModified": 1
+ },
+ "commandName": "bulkWrite"
+ }
+ }
+ ]
+ }
+ ],
+ "outcome": [
+ {
+ "collectionName": "coll0",
+ "databaseName": "crud-tests",
+ "documents": [
+ {
+ "_id": 1,
+ "x": 11
+ },
+ {
+ "_id": 2,
+ "x": 22
+ },
+ {
+ "_id": 3,
+ "x": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/driver-core/src/test/resources/unified-test-format/crud/client-bulkWrite-updateOne-sort.json b/driver-core/src/test/resources/unified-test-format/crud/client-bulkWrite-updateOne-sort.json
new file mode 100644
index 00000000000..ef75dcb3741
--- /dev/null
+++ b/driver-core/src/test/resources/unified-test-format/crud/client-bulkWrite-updateOne-sort.json
@@ -0,0 +1,167 @@
+{
+ "description": "client bulkWrite updateOne-sort",
+ "schemaVersion": "1.4",
+ "runOnRequirements": [
+ {
+ "minServerVersion": "8.0",
+ "serverless": "forbid"
+ }
+ ],
+ "createEntities": [
+ {
+ "client": {
+ "id": "client0",
+ "observeEvents": [
+ "commandStartedEvent",
+ "commandSucceededEvent"
+ ]
+ }
+ },
+ {
+ "database": {
+ "id": "database0",
+ "client": "client0",
+ "databaseName": "crud-tests"
+ }
+ },
+ {
+ "collection": {
+ "id": "collection0",
+ "database": "database0",
+ "collectionName": "coll0"
+ }
+ }
+ ],
+ "initialData": [
+ {
+ "collectionName": "coll0",
+ "databaseName": "crud-tests",
+ "documents": [
+ {
+ "_id": 1,
+ "x": 11
+ },
+ {
+ "_id": 2,
+ "x": 22
+ },
+ {
+ "_id": 3,
+ "x": 33
+ }
+ ]
+ }
+ ],
+ "_yamlAnchors": {
+ "namespace": "crud-tests.coll0"
+ },
+ "tests": [
+ {
+ "description": "client bulkWrite updateOne with sort option",
+ "operations": [
+ {
+ "object": "client0",
+ "name": "clientBulkWrite",
+ "arguments": {
+ "models": [
+ {
+ "updateOne": {
+ "namespace": "crud-tests.coll0",
+ "filter": {
+ "_id": {
+ "$gt": 1
+ }
+ },
+ "sort": {
+ "_id": -1
+ },
+ "update": {
+ "$inc": {
+ "x": 1
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ],
+ "expectEvents": [
+ {
+ "client": "client0",
+ "events": [
+ {
+ "commandStartedEvent": {
+ "commandName": "bulkWrite",
+ "databaseName": "admin",
+ "command": {
+ "bulkWrite": 1,
+ "ops": [
+ {
+ "update": 0,
+ "filter": {
+ "_id": {
+ "$gt": 1
+ }
+ },
+ "updateMods": {
+ "$inc": {
+ "x": 1
+ }
+ },
+ "sort": {
+ "_id": -1
+ },
+ "multi": {
+ "$$unsetOrMatches": false
+ },
+ "upsert": {
+ "$$unsetOrMatches": false
+ }
+ }
+ ],
+ "nsInfo": [
+ {
+ "ns": "crud-tests.coll0"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "commandSucceededEvent": {
+ "reply": {
+ "ok": 1,
+ "nErrors": 0,
+ "nMatched": 1,
+ "nModified": 1
+ },
+ "commandName": "bulkWrite"
+ }
+ }
+ ]
+ }
+ ],
+ "outcome": [
+ {
+ "collectionName": "coll0",
+ "databaseName": "crud-tests",
+ "documents": [
+ {
+ "_id": 1,
+ "x": 11
+ },
+ {
+ "_id": 2,
+ "x": 22
+ },
+ {
+ "_id": 3,
+ "x": 34
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
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 5c925d97272..735c35dc9ed 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
@@ -134,6 +134,7 @@
import static java.util.Arrays.asList;
import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
+import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toList;
@SuppressWarnings("deprecation")
@@ -1607,7 +1608,7 @@ private static SearchIndexModel toIndexSearchModel(final BsonValue bsonValue) {
BsonDocument model = bsonValue.asDocument();
BsonDocument definition = model.getDocument("definition");
SearchIndexType type = model.containsKey("type") ? getSearchIndexType(model.getString("type")) : null;
- String name = Optional.ofNullable(model.getString("name", null))
+ String name = ofNullable(model.getString("name", null))
.map(BsonString::getValue).
orElse(null);
return new SearchIndexModel(name, definition, type);
@@ -1616,7 +1617,7 @@ private static SearchIndexModel toIndexSearchModel(final BsonValue bsonValue) {
OperationResult executeListSearchIndexes(final BsonDocument operation) {
MongoCollection collection = getMongoCollection(operation);
- Optional arguments = Optional.ofNullable(operation.getOrDefault("arguments", null)).map(BsonValue::asDocument);
+ Optional arguments = ofNullable(operation.getOrDefault("arguments", null)).map(BsonValue::asDocument);
if (arguments.isPresent()) {
ListSearchIndexesIterable iterable = createListSearchIndexesIterable(collection, arguments.get());
@@ -1634,7 +1635,7 @@ OperationResult executeListSearchIndexes(final BsonDocument operation) {
private ListSearchIndexesIterable createListSearchIndexesIterable(final MongoCollection collection,
final BsonDocument arguments) {
- Optional name = Optional.ofNullable(arguments.getOrDefault("name", null))
+ Optional name = ofNullable(arguments.getOrDefault("name", null))
.map(BsonValue::asString).map(BsonString::getValue);
ListSearchIndexesIterable iterable = collection.listSearchIndexes(BsonDocument.class);
@@ -1930,6 +1931,9 @@ private static ClientReplaceOneOptions getClientReplaceOneOptions(final BsonDocu
case "upsert":
options.upsert(argument.asBoolean().getValue());
break;
+ case "sort":
+ options.sort(argument.asDocument());
+ break;
default:
throw new UnsupportedOperationException(format("Unsupported argument: key=%s, argument=%s", key, argument));
}
@@ -1938,7 +1942,16 @@ private static ClientReplaceOneOptions getClientReplaceOneOptions(final BsonDocu
}
private static ClientUpdateOneOptions getClientUpdateOneOptions(final BsonDocument arguments) {
- return fillAbstractClientUpdateOptions(new ConcreteClientUpdateOneOptions(), arguments);
+ ConcreteClientUpdateOneOptions options = new ConcreteClientUpdateOneOptions();
+
+ if (arguments.containsKey("sort")) {
+ BsonDocument sort = arguments
+ .remove("sort")
+ .asDocument();
+ options.sort(sort);
+ }
+
+ return fillAbstractClientUpdateOptions(options, arguments);
}
private static ClientUpdateManyOptions getClientUpdateManyOptions(final BsonDocument arguments) {