【发布时间】:2017-09-17 22:29:40
【问题描述】:
我有一个 MongoDB,我在其中记录带有子项数组的项。添加或更新子项时,我先Find主Item,然后将新的SubItem添加到SubItems的数组中,并替换整个Item。在我开始批量插入 SubItems 之前,这工作“很棒”。
我认为我的问题是查找和更新不是一个原子操作,结果是我失去了SubItems。
我正在使用 .NET MongoDB.Driver,我的保存方法如下所示:
public Task Save(string itemId, SubItem subItem)
{
var itemFilter = Builders<Item>.Filter.Eq(v => v.Id, itemId);
var collection = _db.GetCollection<Item>("Items");
var item = await collection.Find(itemFilter).SingleOrDefaultAsync();
item.SubItems.Add(subItem);
collection.ReplaceOneAsync(itemFilter, item, new UpdateOptions() { IsUpsert = true }).Wait();
return Task.FromResult(0);
}
这是我的数据模型:
public class Item
{
public string Id { get; set; }
public List<SubItem> SubItems { get; set; }
}
public class SubItem
{
public string Id { get; set; }
}
有没有办法在一个操作中插入或更新SubItem,这样即使我有多个进程尝试同时更新文档,我也可以确保保持整个Item 文档一致?
【问题讨论】:
-
"upserts" 和数组通常不会很好地混合。典型的情况是使用多个操作(通常是批量)“测试”数组中项目的存在,然后“推送”新项目或“更新”它存在的位置。您可以使用
$addToSet“在某种程度上”简化情况,“如果”数组内容只是值或“单个”属性。但是,如果有多个属性,“唯一性”是指在该上下文中这些属性的组合,它会退回到“测试”方法。 -
“upsert”问题是当任何此类更新需要“测试”数组中元素的存在时,“any”否定结果意味着“upsert”总是在您的实际意图可能已经发生时发生“追加”现有文档的数组而不是新文档。因此,您采用的实际过程实际上取决于您的预期模式。如果您真的想要“upserts”并且想要数组中的多个属性,那么您实际上的意思是要执行“多个操作”。