MongoDB:在路径中找到太多位置(即';$';)元素

MongoDB:在路径中找到太多位置(即';$';)元素,mongodb,Mongodb,我刚刚升级到Mongo2.6.1,之前运行的一条update语句没有返回错误。update语句是: db.post.update( { 'answers.comments.name': 'jeff' }, { '$set': { 'answers.$.comments.$.name': 'joe' }}, { multi: true } ) 我得到的错误是: WriteResult({ "nMatched" : 0, "nUpserted

我刚刚升级到Mongo2.6.1,之前运行的一条update语句没有返回错误。update语句是:

db.post.update( { 'answers.comments.name': 'jeff' },
    { '$set': {
        'answers.$.comments.$.name': 'joe'
    }},
    { multi: true }
)
我得到的错误是:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 2,
        "errmsg" : "Too many positional (i.e. '$') elements found in path 'answers.$.comments.$.createUsername'"
    }
})

当我只更新一个元素一级而不是两级时(即,
answers.$.name
而不是
answers.$.comments.$.name
),它可以正常工作。如果我将mongo实例降级到2.6以下,它也可以正常工作。

位置运算符在查询中只能使用一次。这是一个限制,有一个有待改进的开放票:

答案是

db.post.update( { 'answers.comments.name': 'jeff' },
    { '$set': {
        'answers.0.comments.1.name': 'joe'
    }},
    { multi: true }
)

我也遇到了同样的问题,因为阵列内部的阵列更新需要很大的性能影响。因此,mongo db不支持它。重新设计数据库,如下面给定的链接所示。


如前所述;目前不支持多个位置元素。您可以使用mongodbcursor.forEach()方法更新

db.post
  .find({"answers.comments.name": "jeff"})
  .forEach(function(post) {
    if (post.answers) {
      post.answers.forEach(function(answer) {
        if (answer.comments) {
          answer.comments.forEach(function(comment) {
            if (comment.name === "jeff") {
              comment.name = "joe";
            }
          });
        }
      });

      db.post.save(post);
    }
  });

你可以做到这一点,你只需要Mongo3.6!您可以使用Mongo 3.6中的阵列过滤器功能,而不是重新设计数据库,该功能可以在以下位置找到:

这样做的好处是,您可以将数组中的所有匹配项绑定到一个变量,然后稍后引用该变量。下面是上面链接中的主要示例:


使用
阵列过滤器

MongoDB 3.5.12扩展了所有更新修饰符以应用于所有数组 元素或与谓词匹配的所有数组元素,在 新的更新选项arrayFilters。此语法还支持嵌套数组 元素

让我们假设一个情景-

"access": {
    "projects": [{
        "projectId": ObjectId(...),
        "milestones": [{
            "milestoneId": ObjectId(...),
            "pulses": [{
                "pulseId": ObjectId(...)
            }]
        }]
    }]
}
现在,如果您想为项目中存在的里程碑添加一个脉冲

对于PyMongo,请使用如下数组过滤器-

db.users.update_one({
    "_id": ObjectId(userId)
}, {
    "$push": {
        "access.projects.$[i].milestones.$[j].pulses": ObjectId(pulseId)
    }
}, array_filters = [{
        "i.projectId": ObjectId(projectId)
}, {
        "j.milestoneId": ObjectId(milestoneId)
}])
而且

每个数组筛选器都必须是一个谓词,位于具有单个 字段名。必须在更新表达式中使用每个数组筛选器, 每个阵列筛选器标识符$[]必须具有相应的 阵列过滤器。必须以小写字母开头,且不包含 任何特殊字符。不能有两个具有 相同的字段名

db.post.update(
{'answers.comments.name':'jeff'},
{'$set':{
'答案。$[i].注释。$.name':'乔'
}},
{arrayFilters:[{“i.comments.name”:{$eq:'jeff'}}]}

)
这是当前版本MongoDB(2.6.1)的一个问题,您指定的开放票证是为了解决这个问题,这是正确的。不过,作为一种变通方法,我实际上在Mongo2.4.10中实现了这一点。我现在已经降级了,直到他们解决了这个问题。这个问题是否得到了解决,在v3.2.3中得到了这个错误,你怎么知道它在零位?answers.0.comments.1.name':'joe'不应该是:{$set:{'answers.0.comments.0.name':joe'}。。。在数组中找到的项将始终位于位置0,因为它总是只有一个:与查询条件匹配的项…@ManuelRivera为什么在数组中找到的项始终位于位置0?我不认为这是有意义的。也许在那个时候,我在想,行动只会找到一件物品,而这将是阵列中唯一的一件。但是,现在我发现这不是一个正确的假设。非常好的答案,一个简短的问题,如何确保$[I]中只有一项匹配?假设有多个
i
满足
“i.projectId”:ObjectId(projectId)
,因为使用
$
的最初目的是因为它只匹配数组中的一个项。
db.users.updateOne({
    "_id": ObjectId(userId)
}, {
    "$push": {
        "access.projects.$[i].milestones.$[j].pulses": ObjectId(pulseId)
    }
}, {
    arrayFilters: [{
        "i.projectId": ObjectId(projectId)
    }, {
        "j.milestoneId": ObjectId(milestoneId)
    }]
})
db.users.update_one({
    "_id": ObjectId(userId)
}, {
    "$push": {
        "access.projects.$[i].milestones.$[j].pulses": ObjectId(pulseId)
    }
}, array_filters = [{
        "i.projectId": ObjectId(projectId)
}, {
        "j.milestoneId": ObjectId(milestoneId)
}])