如何使用 Spring+Mongo 更新和添加到子文档列表

How to update and add to subdocument list with Spring+Mongo

我在 MongoDB collection:

中有这样的文档
{
  id : ... 
  listA:[{
          id: ...,
          thing:...,
          listB:[{...},{...}]
          },...
            ]
}

(顶级ID是正常的auto-generated MongoDB ID。子文档的另一个ID object是我单独生成的pseudo-ID并且推入列表)

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

这个 object 可能相当大,并且可能有多个线程在 object 上运行,所以我想避免 findOne,更新,然后 save 场景类型。

我想在 Spring 数据中以类似于我推送到 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);
}

但是我无法生成正确的 Query/Criteria。

提前致谢。

您应该尝试下一个查询:

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");

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

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

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

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

如果你真的想避免这种情况,你应该想到a versioning mechanism or checking old data before updating