programing

MongoDB를 사용하여 중첩된 어레이 업데이트

skycolor 2023. 5. 7. 11:20
반응형

MongoDB를 사용하여 중첩된 어레이 업데이트

중첩된 배열의 값을 업데이트하려고 하지만 작동할 수 없습니다.

제 목적은 이렇습니다.

 {
    "_id": {
        "$oid": "1"
    },
    "array1": [
        {
            "_id": "12",
            "array2": [
                  {
                      "_id": "123",
                      "answeredBy": [],   // need to push "success" 
                  },
                  {
                      "_id": "124",
                      "answeredBy": [],
                  }
             ],
         }
     ]
 }

answeredBy 배열에 값을 푸시해야 합니다.

아래 예제에서는 "123_id" 개체의 "reswsedBy" 배열에 "success" 문자열을 푸시하려고 했지만 작동하지 않습니다.

callback = function(err,value){
     if(err){
         res.send(err);
     }else{
         res.send(value);
     }
};
conditions = {
    "_id": 1,
    "array1._id": 12,
    "array2._id": 123
  };
updates = {
   $push: {
     "array2.$.answeredBy": "success"
   }
};
options = {
  upsert: true
};
Model.update(conditions, updates, options, callback);

는 이 링크를 찾았지만, 답변에는 배열 대신 객체와 같은 구조를 사용해야 한다고만 나와 있습니다.이것은 나의 상황에서는 적용될 수 없습니다.개체를 어레이에 중첩해야 합니다.

여기서 저를 도와주시면 감사하겠습니다.이 문제를 해결하기 위해 몇 시간을 보냈습니다.

잘 부탁드립니다!

일반 범위 및 설명

당신이 여기서 하는 일에는 몇 가지 문제가 있습니다.첫째, 쿼리 조건입니다.당신은 몇 가지를 언급하고 있습니다._id값 중 하나 이상이 최상위 수준이 아닌 값입니다.

된" "내포된" 값을 ._id값은 고유하며 다른 문서에는 나타나지 않습니다. 쿼리 양식은 다음과 같아야 합니다.

Model.update(
    { "array1.array2._id": "123" },
    { "$push": { "array1.0.array2.$.answeredBy": "success" } },
    function(err,numAffected) {
       // something with the result in here
    }
);

이것은 실제로 효과가 있을 것입니다. 하지만 실제로는 운이 좋을 뿐입니다. 여러분에게 효과가 없어야 하는 아주 좋은 이유들이 있기 때문입니다.

중요한 판독치는 위치 연산자에 대한 공식 문서에 "내포 배열"이라는 제목으로 나와 있습니다.이것은 다음을 의미합니다.

$ 자리 표시자의 대체 값이 단일 값이기 때문에 다른 배열 내에 중첩된 배열을 통과하는 쿼리와 같이 둘 이상의 배열을 통과하는 쿼리에는 위치 $ 연산자를 사용할 수 없습니다.

특히 위치 자리 표시자에서 일치하고 반환되는 요소는 첫 번째 일치 배열의 인덱스 값입니다.이는 "최상위" 수준 배열에서 일치하는 인덱스를 의미합니다.

따라서 표시된 쿼리 표기법을 보면 최상위 배열의 첫 번째(또는 0 인덱스) 위치를 "하드코딩"했습니다. "array2" 내의 일치 요소도 0 인덱스 항목입니다.

하는 이를입기위일치항변수있다경니습을 변경할 수 ._id는 "124"입니다.$push에 소에 새항목운로한으로 새 _id은 "표시자에게 입니다."123"은 "array1"과 같은 값입니다.

이것이 네스팅 어레이의 일반적인 문제입니다.레벨 중 하나를 제거할 수 있지만 "상위" 배열에 있는 올바른 요소를 제거할 수는 있지만 여러 레벨이 있습니다.

표시된 대로 업데이트 문제가 발생하므로 배열 중첩을 방지합니다.

일반적인 경우는 "수준"이라고 생각하는 것을 "평평화"하고 실제로 최종 세부 항목에 이러한 "속성"을 만드는 것입니다.예를 들어, 질문에서 구조의 "평판화된" 형태는 다음과 같아야 합니다.

 {
   "answers": [
     { "by": "success", "type2": "123", "type1": "12" }
   ]
 }

또는 내부 배열을 수락하는 경우에도 업데이트되지 않습니다.

 {
   "array": [
     { "type1": "12", "type2": "123", "answeredBy": ["success"] },
     { "type1": "12", "type2": "124", "answeredBy": [] }
   ]
 }

다 위치 연산자의 범위 내에서 원자력 업데이트에 도움이 됩니다.


MongoDB 3.6 이상

MongoDB 3.6에는 중첩된 어레이와 함께 작동할 수 있는 새로운 기능이 있습니다.이는 특정 요소를 일치시키고 다음을 통해 다른 조건을 적용하기 위해 위치 필터링된 구문을 사용합니다.arrayFilters업데이트 문:

Model.update(
  {
    "_id": 1,
    "array1": {
      "$elemMatch": {
        "_id": "12","array2._id": "123"
      }
    }
  },
  {
    "$push": { "array1.$[outer].array2.$[inner].answeredBy": "success" }
  },
  {
    "arrayFilters": [{ "outer._id": "12" },{ "inner._id": "123" }] 
  }
)

"arrayFilters"또는 짝수에 대한 옵션에 전달된 대로, 또는 메서드는 업데이트 문에 지정된 식별자에 대해 일치시킬 조건을 지정합니다.지정된 조건과 일치하는 모든 요소가 업데이트됩니다.

구조가 "내포"되기 때문에 실제로는 표시된 필터 정의의 "어레이"로 지정된 "복수 필터"를 사용합니다.표시된 "식별자"는 문의 업데이트 블록에서 실제로 사용되는 위치 필터링 구문과 일치하는 데 사용됩니다.이 경우inner그리고.outer중첩 체인으로 지정된 각 조건에 사용되는 식별자입니다.

이 새로운 확장 기능을 사용하면 중첩된 어레이 콘텐츠를 업데이트할 수 있지만 이러한 데이터를 "쿼리"하는 데는 실질적으로 도움이 되지 않으므로 앞서 설명한 것과 동일한 주의 사항이 적용됩니다.

여러분은 일반적으로 "속성"으로 표현하는 것을 "의미"로 표현합니다. 여러분의 뇌가 처음에 "둥근"이라고 생각하더라도, 그것은 보통 "이전의 관계적인 부분"이 어떻게 합쳐진다고 믿는지에 대한 반응일 뿐입니다.실제로 당신은 더 많은 비정규화가 필요합니다.

또한 mongodb에서 여러 어레이 요소를 업데이트하는 방법을 참조하십시오. 이러한 새 업데이트 연산자는 위치 업데이트의 이전 작업인 첫 번째 요소가 아닌 "여러 어레이 요소"를 실제로 일치시키고 업데이트합니다.

참고 다소 아이러니하게도, 이것은 다음에 대한 "옵션" 인수에 명시되어 있기 때문입니다..update()메서드와 마찬가지로 이 구문은 일반적으로 모든 최신 릴리스 드라이버 버전과 호환됩니다.

하지만 이것은 사실이 아닙니다.mongo셸, 방법이 그곳에서 구현되기 때문에 (아이러니하게도 "역호환성을 위해")arrayFilters이전 MongoDB 서버 버전과 "레거시"와의 "역호환성"을 제공하기 위해 옵션을 구문 분석하는 내부 방법에 의해 인수가 인식되지 않고 제거됩니다..update()API 호출 구문입니다.

그래서 만약 당신이 에서 명령을 사용하고 싶다면.mongo셸 또는 기타 "쉘 기반" 제품(특히 로보 3T)은 3.6 이상의 개발 지사 또는 프로덕션 릴리스의 최신 버전이 필요합니다.

또한 "여러 배열 요소"를 업데이트하지만 지정된 조건에는 적용되지 않고 원하는 작업인 배열의 모든 요소에 적용되는 항목을 참조하십시오.

저는 이것이 아주 오래된 질문이라는 것을 압니다. 하지만 저는 이 문제와 씨름했고, 제가 믿는 것이 더 나은 답이라는 것을 발견했습니다.

이 문제를 해결하는 방법은 을 사용하는 것입니다.스키마 내에 스키마를 중첩하여 수행합니다.

MainSchema = new mongoose.Schema({
   array1: [Array1Schema]
})

Array1Schema = new mongoose.Schema({
   array2: [Array2Schema]
})

Array2Schema = new mongoose.Schema({
   answeredBy": [...]
})

이렇게 하면 오브젝트가 표시된 오브젝트처럼 보이지만, 이제 각 배열은 하위 문서로 채워집니다.이렇게 하면 원하는 하위 문서로 이동할 수 있습니다.를사는신대를 사용하는 에..update그런 다음 a를 사용합니다..find또는.findOne업데이트할 문서를 가져옵니다.

Main.findOne((
    {
        _id: 1
    }
)
.exec(
    function(err, result){
        result.array1.id(12).array2.id(123).answeredBy.push('success')
        result.save(function(err){
            console.log(result)
        });
    }
)

사용하지 않았습니다..push() 제가 직접 이런 식으로 작동하기 때문에 구문이 올바르지 않을 수 있지만, 저는 두 가지를 모두 사용했습니다..set()그리고..remove()둘 다 완벽하게 잘 작동합니다.

언급URL : https://stackoverflow.com/questions/23577123/updating-a-nested-array-with-mongodb

반응형