spring-data-mongodb
spring-data-mongodb copied to clipboard
With HASH sharding strategy the filter which participate in update operation is incorrect
In MongoTemplate when executing collectionToUse.replaceOne(filter, replacement, new ReplaceOptions().upsert(true)); after applying ShardKey the filter looks like this
{
_id=15003b6e6b8a41afa458dd5696cced6b,
customer=hash
}
and I am getting this exception
Write operation error on server
My annotation on the entity looks like this
@Sharded(shardKey = {"customer", "_id"}, shardingStrategy = ShardingStrategy.HASH)
Thanks for reporting. Which version of spring-data are you using? Also please share a bit more information about the domain types involved and the calling code. A complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem would be nice.
I am using spring-boot-starter-data-mongodb - 2.6.6 where spring-data-mongodb's version is 3.3.3.
I have a Task entity
@Sharded(shardKey = {"_id", "customer"})
@Document(collection = "task")
public class Task {
@Id
private String id;
private String name;
private String description;
@Indexed
private String customer;
}
which I am trying to update calling
taskRepository.save(task);
TaskRepository looks like this
public interface TaskRepository extends MongoRepository<Task, String> {
}
In documentation it is said that
Spring Data adds the shard key to filter queries used for replaceOne operations triggered by save operations
But in MongoTemplate when executing collectionToUse.replaceOne(filter, replacement, new ReplaceOptions().upsert(true)); after applying ShardKey the filter looks like this
{
_id=15003b6e6b8a41afa458dd5696cced6b,
customer=hash
}
customer value is lost.
Thanks for providing more information. I might be missing something but it looks as if everything behaves within defined boundaries. Please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem. Maybe it's just setting ShardKey#immutableKey to true that needs to be done.
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Hi, I have the same problem like @tigrantovmasyan. My version is Spring Boot 2.7.2, Spring data mongo 3.4.2
I try to explane my scenario (my cloud application is multi-tenancy and I use the tenantId as shard key):
This is the document entity:
@Document("products")
@Sharded(shardKey = { "tenantId"}, shardingStrategy = ShardingStrategy.HASH)
public class Product implements Serializable {
@Id
private ObjectId id;
private String tenantId;
private String sku;
private String productId;
/* and other properties*/
}
My code is very simple, I read the product from MongoDB (version 6.0) with find
private Product findProduct(String productId, String tenantId) {
Query query = new Query();
query.addCriteria(Criteria.where("tenantId").is(tenantId));
query.addCriteria(Criteria.where("productId").is(productId));
return mongoTemplate.find(query, Product .class);
}
Find the product, set sku and save
Product p = findProduct("123", "tenantX");
p.setSku("123456");
mongoTemplate.save(p); //here thows an Exception WriteError{code=11000, message='E11000 duplicate key error collection
I investigated inside source code and seems the issue is in MongoTemplate.java inside method saveDocument
if (updateContext.requiresShardKey(filter, entity)) {
if (entity.getShardKey().isImmutable()) {
filter = updateContext.applyShardKey(entity, filter, null);
} else {
filter = updateContext.applyShardKey(entity, filter,
collection.find(filter, Document.class).projection(updateContext.getMappedShardKey(entity)).first());
}
}
the filter when the shardKey in not Immutable is modified, after "updateContext.applyShardKey"
{
"id": ObjectId(id_oj_row)
"tenantId": "shard" //I suppose this is the issue, the value of tenantId filter is not tenantX in my scenario
}
Thanks