BulkWriteSupport.java
/*
* Copyright 2026-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import java.util.List;
import org.bson.Document;
import org.springframework.util.ClassUtils;
import com.mongodb.MongoNamespace;
import com.mongodb.client.model.DeleteManyModel;
import com.mongodb.client.model.DeleteOneModel;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.ReplaceOneModel;
import com.mongodb.client.model.ReplaceOptions;
import com.mongodb.client.model.UpdateManyModel;
import com.mongodb.client.model.UpdateOneModel;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.WriteModel;
import com.mongodb.client.model.bulk.ClientDeleteManyOptions;
import com.mongodb.client.model.bulk.ClientDeleteOneOptions;
import com.mongodb.client.model.bulk.ClientNamespacedWriteModel;
import com.mongodb.client.model.bulk.ClientReplaceOneOptions;
import com.mongodb.client.model.bulk.ClientUpdateManyOptions;
import com.mongodb.client.model.bulk.ClientUpdateOneOptions;
/**
* @author Christoph Strobl
*/
abstract class BulkWriteSupport {
static WriteModel<Document> updateMany(Document query, Object update, UpdateOptions updateOptions) {
if (update instanceof List<?> pipeline) {
return new UpdateManyModel<>(query, (List<Document>) pipeline, updateOptions);
} else if (update instanceof Document updateDocument) {
return new UpdateManyModel<>(query, updateDocument, updateOptions);
} else {
throw new IllegalArgumentException(
"Update needs to be either a List or a Document, but was [%s]".formatted(ClassUtils.getUserClass(update)));
}
}
static WriteModel<Document> updateOne(Document query, Object update, UpdateOptions updateOptions) {
if (update instanceof List<?> pipeline) {
return new UpdateOneModel<>(query, (List<Document>) pipeline, updateOptions);
} else if (update instanceof Document updateDocument) {
return new UpdateOneModel<>(query, updateDocument, updateOptions);
} else {
throw new IllegalArgumentException(
"Update needs to be either a List or a Document, but was [%s]".formatted(ClassUtils.getUserClass(update)));
}
}
static WriteModel<Document> removeMany(Document query, DeleteOptions deleteOptions) {
return new DeleteManyModel<>(query, deleteOptions);
}
static WriteModel<Document> removeOne(Document query, DeleteOptions deleteOptions) {
return new DeleteOneModel<>(query, deleteOptions);
}
static WriteModel<Document> replaceOne(Document query, Document replacement, UpdateOptions updateOptions) {
ReplaceOptions replaceOptions = new ReplaceOptions();
replaceOptions.collation(updateOptions.getCollation());
replaceOptions.upsert(updateOptions.isUpsert());
replaceOptions.sort(updateOptions.getSort());
replaceOptions.hint(updateOptions.getHint());
replaceOptions.hintString(updateOptions.getHintString());
return new ReplaceOneModel<>(query, replacement, replaceOptions);
}
static ClientNamespacedWriteModel updateMany(MongoNamespace namespace, Document query, Object update,
UpdateOptions updateOptions) {
ClientUpdateManyOptions updateManyOptions = ClientUpdateManyOptions.clientUpdateManyOptions();
updateManyOptions.arrayFilters(updateOptions.getArrayFilters());
updateManyOptions.collation(updateOptions.getCollation());
updateManyOptions.upsert(updateOptions.isUpsert());
updateManyOptions.hint(updateOptions.getHint());
updateManyOptions.hintString(updateOptions.getHintString());
if (update instanceof List<?> pipeline) {
return ClientNamespacedWriteModel.updateMany(namespace, query, (List<Document>) pipeline, updateManyOptions);
} else if (update instanceof Document updateDocument) {
return ClientNamespacedWriteModel.updateMany(namespace, query, updateDocument, updateManyOptions);
} else {
throw new IllegalArgumentException(
"Update needs to be either a List or a Document, but was [%s]".formatted(ClassUtils.getUserClass(update)));
}
}
static ClientNamespacedWriteModel updateOne(MongoNamespace namespace, Document query, Object update,
UpdateOptions updateOptions) {
ClientUpdateOneOptions updateOneOptions = ClientUpdateOneOptions.clientUpdateOneOptions();
updateOneOptions.sort(updateOptions.getSort());
updateOneOptions.arrayFilters(updateOptions.getArrayFilters());
updateOneOptions.collation(updateOptions.getCollation());
updateOneOptions.upsert(updateOptions.isUpsert());
updateOneOptions.hint(updateOptions.getHint());
updateOneOptions.hintString(updateOptions.getHintString());
if (update instanceof List<?> pipeline) {
return ClientNamespacedWriteModel.updateOne(namespace, query, (List<Document>) pipeline, updateOneOptions);
} else if (update instanceof Document updateDocument) {
return ClientNamespacedWriteModel.updateOne(namespace, query, updateDocument, updateOneOptions);
} else {
throw new IllegalArgumentException(
"Update needs to be either a List or a Document, but was [%s]".formatted(ClassUtils.getUserClass(update)));
}
}
static ClientNamespacedWriteModel removeMany(MongoNamespace namespace, Document query, DeleteOptions deleteOptions) {
ClientDeleteManyOptions clientDeleteManyOptions = ClientDeleteManyOptions.clientDeleteManyOptions();
clientDeleteManyOptions.collation(deleteOptions.getCollation());
clientDeleteManyOptions.hint(deleteOptions.getHint());
clientDeleteManyOptions.hintString(deleteOptions.getHintString());
return ClientNamespacedWriteModel.deleteMany(namespace, query, clientDeleteManyOptions);
}
static ClientNamespacedWriteModel removeOne(MongoNamespace namespace, Document query, DeleteOptions deleteOptions) {
ClientDeleteOneOptions clientDeleteOneOptions = ClientDeleteOneOptions.clientDeleteOneOptions();
// TODO: open an issue with MongoDB to enable sort for deleteOne
clientDeleteOneOptions.collation(deleteOptions.getCollation());
clientDeleteOneOptions.hint(deleteOptions.getHint());
clientDeleteOneOptions.hintString(deleteOptions.getHintString());
return ClientNamespacedWriteModel.deleteOne(namespace, query, clientDeleteOneOptions);
}
static ClientNamespacedWriteModel replaceOne(MongoNamespace namespace, Document query, Document replacement,
UpdateOptions updateOptions) {
ClientReplaceOneOptions replaceOptions = ClientReplaceOneOptions.clientReplaceOneOptions();
replaceOptions.sort(updateOptions.getSort());
replaceOptions.upsert(updateOptions.isUpsert());
replaceOptions.hint(updateOptions.getHint());
replaceOptions.hintString(updateOptions.getHintString());
replaceOptions.collation(updateOptions.getCollation());
return ClientNamespacedWriteModel.replaceOne(namespace, query, replacement, replaceOptions);
}
}