3

我在 MongoDB 集合中有这样的文档:

{
  id : ... 
  listA:[{
          id: ...,
          thing:...,
          listB:[{...},{...}]
          },...
            ]
}

(顶层ID是正常的自动生成的MongoDB ID。子文档对象的另一个ID是我单独生成并推入列表的伪ID)

问题:我想(1)添加listB和(2)改变thing

该对象可能非常庞大,并且可能有多个线程在该对象上运行,因此我想避免出现findOne, update, thensave类型的场景。

我想在 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);
}

但是我无法生成正确的查询/标准。

提前致谢。

4

2 回答 2

10

您应该尝试下一个查询:

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");
于 2016-02-27T16:34:08.330 回答
3

我认为您混淆了两个概念:

  • 在原子操作中进行 2 次更新。
  • 替换整个文档。

我了解您出于性能原因只想更新而不是替换,因此接受的答案是正确的。

但是,另一方面,findOne - save机制是完全线程安全的,因为这两个更新发生在保存操作上,当整个文档被替换时。因此,如果在findOne保存操作之间有另一个线程修改您的文档,您的文档将被正确替换为最新版本。然后,当然你有一个问题,因为在第二位替换的线程不会被通知第一次修改,但你也有这个问题与接受的解决方案

如果你真的想避免这种情况,你应该考虑一个版本控制机制或者在更新之前检查旧数据

于 2017-07-18T11:27:22.943 回答