sourcecode

MongoDB: 경로에 위치(예: '$') 요소가 너무 많습니다.

copyscript 2023. 6. 23. 22:22
반응형

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), 잘 작동합니다.내 몽고 인스턴스를 2.6 이하로 다운그레이드하면 역시 잘 작동합니다.

사용하다arrayFilters.

MongoDB 3.5.12는 새 업데이트 옵션 arrayFilters에 지정된 술어와 일치하는 모든 어레이 요소 또는 모든 어레이 요소에 적용할 수 있도록 모든 업데이트 한정자를 확장합니다.이 구문은 중첩된 배열 요소도 지원합니다.

시나리오를 가정해보죠

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

프로젝트 내부에 존재하는 마일스톤펄스를 추가하려면

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

Mongo 3.6만 있으면 됩니다! 데이터베이스를 재설계하는 대신 Mongo 3.6의 어레이 필터 기능을 사용할 수 있습니다. 이 기능은 다음과 같습니다.

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

배열의 모든 일치 항목을 변수에 바인딩한 다음 나중에 해당 변수를 참조할 수 있습니다.다음은 위 링크의 주요 예입니다.

enter image description here

위치 연산자는 쿼리에서 한 번만 사용할 수 있습니다.이것은 제한 사항입니다. 개선을 위한 공개 티켓이 있습니다. https://jira.mongodb.org/browse/SERVER-831

언급한 바와 같이 현재 둘 이상의 위치 요소가 지원되지 않습니다.() 메서드에 대해 mongodb 커서를 사용하여 업데이트할 수 있습니다.

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

    db.post.update(
    { 'answers.comments.name': 'jeff' },
    { '$set': {
        'answers.$[i].comments.$.name': 'joe'
    }},
    {arrayFilters: [ { "i.comments.name": { $eq: 'jeff' } } ]}
)
check path after answers for get key path right

어레이 업데이트 시 성능에 큰 영향을 미치는 어레이와 동일한 문제가 발생했습니다.그래서 몽고드는 그것을 지원하지 않습니다.아래 지정된 링크에 표시된 대로 데이터베이스를 다시 설계합니다.

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

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

언급URL : https://stackoverflow.com/questions/24046470/mongodb-too-many-positional-i-e-elements-found-in-path

반응형