2016-02-27 37 views
1

我有一個MongoDB中收集這樣的文件:如何更新和添加到子文檔列表與Spring +蒙戈

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

(頂層ID是正常的自動生成的MongoDB ID的其他ID子文檔對象的是,我已經單獨地生成並推入列表)

問題的僞ID:我想(1)添加到listB和(2)變化thing

釷對象可能非常沉重,並且有可能多個線程可能在對象上運行,所以我想避免findOne,更新,然後save類型的場景。

我想,我已經做了推動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); 
} 

但是我無法生成正確的查詢/標準。

在此先感謝。

回答

3

你應該嘗試下一個查詢:

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

的感謝,我會一展身手。即使字段名稱是「id」而不是mongo ID,它總是「_id」嗎? –

+1

@ user2393012不確定它應該是您的密鑰名稱.where(「keyName」)。is(「value」) –

1

我想你混淆了概念2:

  • 在一個原子操作使2次更新。
  • 替換整個文檔。

據我所知,你只是想更新而不是替換的性能原因,所以接受的答案是正確的。

但是,在另一方面,該機制findOne - 保存完全是線程安全的,因爲這兩個更新發生在保存操作,整個文件被替換時。因此,如果在findOne保存操作之間有另一個線程正在修改您的文檔,則您的文檔將被最新版本正確替換。然後,當然,你有一個問題,因爲第二個替換的線程將不會被通知第一個修改,,但您也可以接受解決方案這個問題。

如果你真的想避免這種情況,你應該考慮a versioning mechanism or checking old data before updating