我有以下系列:
{
"Milestones" : [
{ "ActualDate" : null,
"Index": 0,
"Name" : "milestone1",
"TargetDate" : ISODate("2011-12-13T22:00:00Z"),
"_id" : ObjectId("4ee89ae7e60fc615c42e28d1")},
{ "ActualDate" : null,
"Index" : 0,
"Name" : "milestone2",
"TargetDate" : ISODate("2011-12-13T22:00:00Z"),
"_id" : ObjectId("4ee89ae7e60fc615c42e28d2") } ]
,
"Name" : "a", "_id" : ObjectId("4ee89ae7e60fc615c42e28ce")
}
我想更新明确的文档:已指定_id,列表里程碑._id和ActualDate为空。 我dotnet我的代码看起来像:
var query = Query.And(new[] { Query.EQ("_id", ObjectId.Parse(projectId)),
Query.In("Milestones._id", new BsonArray(values.Select(ObjectId.Parse))),
Query.EQ("Milestones.ActualDate", BsonNull.Value) });
var update = Update.Set("Milestones.$.ActualDate", DateTime.Now.Date);
Coll.Update(query, update, UpdateFlags.Multi, SafeMode.True);
或者使用本机代码:
db.Projects.update({ "_id" : ObjectId("4ee89ae7e60fc615c42e28ce"), "Milestones._id" : { "$in" : [ObjectId("4ee89ae7e60fc615c42e28d1"), ObjectId("4ee89ae7e60fc615c42e28d2"), ObjectId("4ee8a648e60fc615c41d481e")] }, "Milestones.ActualDate" : null },{ "$set" : { "Milestones.$.ActualDate" : ISODate("2011-12-13T22:00:00Z") } }, false, true)
但只有第一项正在更新。
答案 0 :(得分:10)
目前这是不可能的。更新中的标记multi
表示更新多个根文档。位置运算符只能匹配一个嵌套数组项。在mongodb jira中有这样的feature。你可以投票并等待。
当前解决方案只能加载文档,根据需要更新,并为每个嵌套数组ID保存或多次原子更新。
来自mongodb.org的文档:
目前,$运算符仅适用于第一个匹配的项目 查询
答案 1 :(得分:1)
正如Andrew Orsich所回答的那样,目前这是不可能的,至少不是你想要的。但是加载文档,修改数组然后将其保存回来将会起作用。风险在于其他一些进程可能在此期间修改数组,因此您将覆盖其更改。为避免这种情况,您可以使用乐观锁定,尤其是在每秒都不修改数组时。
milestones_version
保存回mongodb,但现在在milestones_version
上添加一个查询约束,并将其递增:
db.Projects.findAndModify({
query: {
_id: your_project_id,
milestones_version: expected_milestones_version
},
update: {
$set: {
Milestones: modified_milestones
},
$inc: {
milestones_version: 1
}
},
new: 1
})
如果另一个进程在我们执行之前修改了里程碑数组(以及milestones_version
),则此命令将不执行任何操作,只返回null。我们只需要重新加载文档然后再试一次。如果阵列没有每秒修改一次,那么这将非常罕见,并且不会对性能产生任何影响。
此解决方案的主要问题是您必须逐个编辑每个项目(无multi: true
)。你仍然可以写一个javascript函数,让它在服务器上运行。
答案 2 :(得分:0)
根据他们的JIRA页面"这个新功能从MongoDB 3.5.12开发版本开始提供,并包含在MongoDB 3.6生产版本中#34;