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

时间:2014-06-04 19:59:05

标签: mongodb

我刚刚升级到Mongo 2.6.1,之前正在运行的一个更新语句没有返回错误。更新声明是:

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以下,它也可以正常工作。

7 个答案:

答案 0 :(得分:11)

位置运算符只能在查询中使用一次。这是一个限制,有一个开放的改进票:https://jira.mongodb.org/browse/SERVER-831

答案 1 :(得分:4)

如上所述;现在不支持多个位置元素。您可以使用mongodb cursor.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);
    }
  });

答案 2 :(得分:1)

我面临同样的问题,因为阵列更新中的as数组需要很大的性能影响。所以,mongo db doest不支持它。重新设计您的数据库,如下面给出的链接所示。

https://pythonolyk.wordpress.com/2016/01/17/mongodb-update-nested-array-using-positional-operator/

答案 3 :(得分:1)

您可以这样做,您只需要Mongo 3.6!您可以使用Mongo 3.6中的“数组过滤器”功能来重新设计数据库,而无需重新设计数据库,该功能可在以下位置找到:

https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters

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

enter image description here

答案 4 :(得分:1)

使用arrayFilters

  

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

让我们假设一个场景-

"access": {
    "projects": [{
        "projectId": ObjectId(...),
        "milestones": [{
            "milestoneId": ObjectId(...),
            "pulses": [{
                "pulseId": ObjectId(...)
            }]
        }]
    }]
}

现在,如果要向项目

中存在的里程碑添加 pulse
db.users.updateOne({
    "_id": ObjectId(userId)
}, {
    "$push": {
        "access.projects.$[i].milestones.$[j].pulses": ObjectId(pulseId)
    }
}, {
    arrayFilters: [{
        "i.projectId": ObjectId(projectId)
    }, {
        "j.milestoneId": ObjectId(milestoneId)
    }]
})

对于 PyMongo ,请使用像这样的arrayFilters-

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)
}])

  

每个数组过滤器必须是单个文档的谓词   字段名称。必须在更新表达式中使用每个数组过滤器,   并且每个数组过滤器标识符$ []必须具有一个对应的   数组过滤器。必须以小写字母开头且不包含   任何特殊字符。不得使用两个数组过滤器   相同的字段名称。

https://jira.mongodb.org/browse/SERVER-831

答案 5 :(得分:0)

    db.post.update(
    { 'answers.comments.name': 'jeff' },
    { '$set': {
        'answers.$[i].comments.$.name': 'joe'
    }},
    {arrayFilters: [ { "i.comments.name": { $eq: 'jeff' } } ]}
)
检查 answers 之后的路径以获得正确的关键路径

答案 6 :(得分:-4)

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

答案是

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