我在MongoDB集合中有这样的文档:
{
id : ...
listA:[{
id: ...,
thing:...,
listB:[{...},{...}]
},...
]
}
(顶级ID是正常的自动生成的MongoDB ID。子文档对象的另一个ID是我单独生成并推入列表的伪ID)
问题:我想(1)添加到listB
和(2)更改thing
这个对象可能非常大,并且可能有多个线程可能在对象上运行,因此我想避免findOne
,更新,然后save
类型的场景。
我想在Spring Data中执行此操作,方法与我listA
相似,即
@Autowired
private MongoOperations operations;
public void addStuff(String id, Stuff stuff) {
operations.updateFirst(Query.query(Criteria.where("_id").is(id)),
new Update().addToSet("listA", stuff), Stuffs.class);
}
但是我无法生成正确的查询/标准。
提前致谢。
答案 0 :(得分:5)
您应该尝试下一个查询:
final Query query = new Query(new Criteria().andOperator(
Criteria.where("_id").is("id"),
Criteria.where("listA").elemMatch(Criteria.where("_id").is("id"))
));
final Update update = new Update().addToSet("listA.$.listB", stuff).set("listA.$.thing", "thing");
final WriteResult wr = mongoOperations.updateFirst(query, update, "collectionName");
答案 1 :(得分:3)
我认为你混淆了两个概念:
我知道您只是想更新而不是因为性能原因而更换,所以接受的答案是正确的。
但是,另一方面, findOne - save 机制完全是线程安全的,因为当整个文档是 save 操作时,两个更新发生了。更换。因此,如果在 findOne 和 save 操作之间存在另一个修改文档的线程,则您的文档将被最新版本正确替换。然后,当然你有一个问题,因为第二次替换的线程不会被通知第一次修改,但你也接受了解决方案的问题。
如果你真的想避免这种情况,你应该考虑a versioning mechanism or checking old data before updating