복붙노트

[MONGODB] 어떻게하여 MongoDB의 다중 배열 요소를 업데이트하는

MONGODB

어떻게하여 MongoDB의 다중 배열 요소를 업데이트하는

I 요소의 배열을 유지하는 몽고 문헌이있다.

나는 .profile에이 XX을 = 배열에있는 모든 개체의 .handled 속성을 다시 설정하고 싶습니다.

문서 형식은 다음과 같습니다

{
    "_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
    "user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
    "events": [{
            "handled": 1,
            "profile": 10,
            "data": "....."
        } {
            "handled": 1,
            "profile": 10,
            "data": "....."
        } {
            "handled": 1,
            "profile": 20,
            "data": "....."
        }
        ...
    ]
}

그래서, 나는 다음을 시도 :

.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)

그러나 각 문서의 첫 번째 일치하는 배열 요소를 갱신한다. (즉 $에 대해 정의 된 행동이다 - 위치 연산자를 사용합니다.)

어떻게 모든 일치하는 배열 요소를 업데이트 할 수 있습니다?

해결법

  1. ==============================

    1.이때는 어레이 내의 모든 아이템을 업데이트하는 위치 연산자를 사용하는 것은 불가능하다. 참조 JIRA http://jira.mongodb.org/browse/SERVER-1243

    이때는 어레이 내의 모든 아이템을 업데이트하는 위치 연산자를 사용하는 것은 불가능하다. 참조 JIRA http://jira.mongodb.org/browse/SERVER-1243

    당신이 할 수있는 주위의 작품으로 :

  2. ==============================

    2.무엇 나를 위해 일한 것은이 있었다 :

    무엇 나를 위해 일한 것은이 있었다 :

    db.collection.find({ _id: ObjectId('4d2d8deff4e6c1d71fc29a07') })
      .forEach(function (doc) {
        doc.events.forEach(function (event) {
          if (event.profile === 10) {
            event.handled=0;
          }
        });
        db.collection.save(doc);
      });
    

    나는 JQuery와 친구들을 잘 알고 몽고의 초보자 및 사람에 대한 명확한 생각합니다.

  3. ==============================

    3.(MongoDB를 3.5.12에서 개발 분기 및 사용 가능) MongoDB를 3.6의 출시와 함께 이제 하나의 요청에서 여러 배열 요소를 업데이트 할 수 있습니다.

    (MongoDB를 3.5.12에서 개발 분기 및 사용 가능) MongoDB를 3.6의 출시와 함께 이제 하나의 요청에서 여러 배열 요소를 업데이트 할 수 있습니다.

    이것은 [<식별자>] 업데이트 연산자 구문이 버전에서 도입 여과 위치 $를 사용

    db.collection.update(
      { "events.profile":10 },
      { "$set": { "events.$[elem].handled": 0 } },
      { "arrayFilters": [{ "elem.profile": 10 }], "multi": true }
    )
    

    (.update를위한 옵션에 전달) 또는 같이 "arrayFilters" .updateOne () .updateMany () .findOneAndUpdate () 또는 .bulkWrite () 메소드를 지정 조건은 갱신 명령에 주어진 식별자하였습니다. 주어진 조건과 일치하는 요소가 업데이트됩니다.

    아직이 "여러 요소를 업데이트 할"것이라고 질문의 맥락에서 주어진대로 "다"는 기대에 사용되었지만이 아니었다 것을 주목하는 것은 아니다. 그것의 사용은 여기에 항상 사건이었다 또는 지금 다른 현대 API 버전 .updateMany ()의 필수 설정으로 지정된 것처럼 "여러 문서"에 적용됩니다.

    참고 또한 업데이트 "다수의 배열 요소"그러나 특정 조건에 적용하지 않고 해당 원하는 액션 인 어레이의 모든 요소들에 적용되는 모든 $를 [] 위치.

    또한이 새로운 위치 운영자는 "배열이 다른 배열 내에있는" "중첩"배열 구조에 어떻게 적용되는지에 대한 MongoDB를 함께 중첩 된 배열 업데이트를 참조하십시오.

  4. ==============================

    4.이것은 또한 모든 문서가 여전히 업데이트되지 않은 하위 문서가 남아 있으면 여부를 확인하는 동안 루프를 수행 할 수 있습니다. 이 방법은 업데이트의 자성을 (여기에 다른 솔루션의 대부분이 그렇지 않은) 유지합니다.

    이것은 또한 모든 문서가 여전히 업데이트되지 않은 하위 문서가 남아 있으면 여부를 확인하는 동안 루프를 수행 할 수 있습니다. 이 방법은 업데이트의 자성을 (여기에 다른 솔루션의 대부분이 그렇지 않은) 유지합니다.

    var query = {
        events: {
            $elemMatch: {
                profile: 10,
                handled: { $ne: 0 }
            }
        }
    };
    
    while (db.yourCollection.find(query).count() > 0) {
        db.yourCollection.update(
            query,
            { $set: { "events.$.handled": 0 } },
            { multi: true }
        );
    }
    

    루프 프로필 회 하위의 최대 수와 동일 할 것이다 실행 횟수 (10)와 동일한 0이 컬렉션 내의 문서 중 어느 하나에 발생하는 처리와 같지. 그래서 만약 당신이 컬렉션에 100 개 문서가 매치 쿼리 및 다른 모든 문서를 적은 일치하는 하위 문서를 가지고 그들 중 하나가 세 개의 하위 문서가있는 경우, 루프는 세 번 실행됩니다.

    이 방법은 스크립트의 실행되는 동안 다른 프로세스에 의해 갱신 될 수있는 다른 데이터를 건드리지의 위험을 피할 수있다. 또한, 데이터의 양이 클라이언트와 서버간에 전송되는 최소화한다.

  5. ==============================

    5.이 사실에서와 도전의 숫자가 명확한 구문 사실이 있습니다 http://jira.mongodb.org/browse/SERVER-1243의 오랜 문제와 관련된 그하여 여러개의 배열 일치가 지원하는 "모든 경우에" 녹이다. 이미 사실상의 방법에있다 등이 원래의 게시물 이후에 구현 된 대량의 작업으로이 문제에 대한 해결책에 "원조"그.

    이 사실에서와 도전의 숫자가 명확한 구문 사실이 있습니다 http://jira.mongodb.org/browse/SERVER-1243의 오랜 문제와 관련된 그하여 여러개의 배열 일치가 지원하는 "모든 경우에" 녹이다. 이미 사실상의 방법에있다 등이 원래의 게시물 이후에 구현 된 대량의 작업으로이 문제에 대한 해결책에 "원조"그.

    너무도으로, 더 하나의 업데이트 문에서 하나의 일치하는 배열 요소보다 업데이트하는 것은 여전히 ​​불가능하다 당신이 이제까지 업데이트 할 수 있습니다 모두가 하나의 각 문서의 배열 한 mathed 요소 업데이트는 "멀티" 성명서.

    현재 최선의 가능한 해결책은 일치하는 모든 문서와 적어도 많은 작업이 단수 응답 단일 요청으로 전송 될 수 있도록 프로세스 대량 업데이트를 검색 루프하는 것입니다. 선택적 업데이트 선택을위한 조건과 일치하는 단지 사람들에게 검색 결과에 반환 된 배열 함량을 줄이기 위해 .aggregate ()를 사용할 수 있습니다 :

    db.collection.aggregate([
        { "$match": { "events.handled": 1 } },
        { "$project": {
            "events": {
                "$setDifference": [
                   { "$map": {
                       "input": "$events",
                       "as": "event",
                       "in": {
                           "$cond": [
                               { "$eq": [ "$$event.handled", 1 ] },
                               "$$el",
                               false
                           ]
                       }
                   }},
                   [false]
                ]
            }
        }}
    ]).forEach(function(doc) {
        doc.events.forEach(function(event) {
            bulk.find({ "_id": doc._id, "events.handled": 1  }).updateOne({
                "$set": { "events.$.handled": 0 }
            });
            count++;
    
            if ( count % 1000 == 0 ) {
                bulk.execute();
                bulk = db.collection.initializeOrderedBulkOp();
            }
        });
    });
    
    if ( count % 1000 != 0 )
        bulk.execute();
    

    배열의 각 요소에 대한 모든 컨텐츠의 "고유"식별자는 "고유"요소 자체를 형성하고있을 때 .aggregate () 부분이 동작한다. 이것은 $ setDifference의 "세트"연산자에 일치하는 배열을 처리하는 데 사용되는 맵 $ 동작으로부터 반환 된 오류 값을 필터링하는 데에 기인한다.

    배열의 내용이 독특한 요소가없는 경우에 당신은 $의 편집하다와 다른 접근 방법을 시도 할 수 있습니다 :

    db.collection.aggregate([
        { "$match": { "events.handled": 1 } },
        { "$redact": {
            "$cond": {
                "if": {
                    "$eq": [ { "$ifNull": [ "$handled", 1 ] }, 1 ]
                },
                "then": "$$DESCEND",
                "else": "$$PRUNE"
            }
        }}
    ])
    

    그것의 한계는 "처리"이라면 당신은 가능성이 unexepected 결과를 얻을 수하려고하는 다른 문서 수준에서 존재하는 의미 필드가 사실 이었지만, 그 필드는 하나 개의 문서 위치에 표시하고 평등 일치 좋은 것을입니다.

    향후 자료 작성 등 (이후 3.1 MongoDB를)은 간단 달러 (A $) 필터 작업을해야합니다 :

    db.collection.aggregate([
        { "$match": { "events.handled": 1 } },
        { "$project": {
            "events": {
                "$filter": {
                    "input": "$events",
                    "as": "event",
                    "cond": { "$eq": [ "$$event.handled", 1 ] }
                }
            }
        }}
    ])
    

    그리고 지원 .aggregate은 () $ 언 와인드 다음과 같은 방법을 사용할 수 있지만 운영자의 사용으로 인해 파이프 라인의 배열 확장에에게 가장 효율적인 접근 방식을 만드는 모든 릴리스 :

    db.collection.aggregate([
        { "$match": { "events.handled": 1 } },
        { "$unwind": "$events" },
        { "$match": { "events.handled": 1 } },
        { "$group": {
            "_id": "$_id",
            "events": { "$push": "$events" }
        }}        
    ])
    

    MongoDB의 버전이 집계 출력에서 ​​"커서"를 지원하는 모든 경우에, 다음이 접근 방식을 선택하고 대량 업데이트 문을 처리하는 것으로 동일한 코드 블록과 결과를 반복의 문제이다. 대량 작업 골재 출력에서 ​​"커서"는 처리를 위해 손의 동일한 버전 (MongoDB를 2.6) 때문에, 일반적으로 작업 손에 도입된다.

    심지어 이전 버전에서는 다음 그냥 사용에 아마 최상이다 .find () 배열 요소가 .update를 위해 일치 배의 단지 수에 문 실행 밖으로 커서 및 필터를 () 반복으로 돌아 가기 :

    db.collection.find({ "events.handled": 1 }).forEach(function(doc){ 
        doc.events.filter(function(event){ return event.handled == 1 }).forEach(function(event){
            db.collection.update({ "_id": doc._id },{ "$set": { "events.$.handled": 0 }});
        });
    });
    

    당신이 aboslutely "멀티"업데이트를 수행하기로 결정하거나 각 일치하는 문서에 대해 여러 업데이트를 처리하는 것보다 궁극적으로 더 효율적으로 간주하는 경우, 당신은 항상 가능 배열 일치의 최대 수를 결정할 수 있으며, 단지 많은하는 "멀티"업데이 트를 실행 시간은 기본적으로까지 업데이트 할 이상의 문서가 있습니다.

    MongoDB를 2.4 및 2.2 버전에 대한 올바른 접근 방식은이 값을 찾기 위해 .aggregate ()를 사용할 수 있습니다 :

    var result = db.collection.aggregate([
        { "$match": { "events.handled": 1 } },
        { "$unwind": "$events" },
        { "$match": { "events.handled": 1 } },
        { "$group": {
            "_id": "$_id",
            "count": { "$sum": 1 }
        }},
        { "$group": {
            "_id": null,
            "count": { "$max": "$count" }
        }}
    ]);
    
    var max = result.result[0].count;
    
    while ( max-- ) {
        db.collection.update({ "events.handled": 1},{ "$set": { "events.$.handled": 0 }},{ "multi": true })
    }
    

    어떤 경우, 업데이트 내에서 수행 할 수없는 몇 가지 사항이 있습니다 :

    하나의 갱신 명령으로 처리하는 다수의 유사한 배열 요소들을 허용하는 결정된 적절한 구문이있을 때까지 그럼 기본적인 접근법은 최대의 배열 요소를 작동 본질적 (이상적 벌크) 또는 indvidual 문의 각 유사한 배열 요소 중 하나 업데이트하는 것 갱신 또는 킵 업데이트에 더 이상 수정 결과가 반환되지 않을 때까지. 어쨌든, 당신은 "항상"그는 문마다 하나 개의 요소를 업데이트하는 경우에도 일치하는 배열 요소에 위치 $ 업데이트를 처리해야한다.

    단지 그럼 물론 구현되어, 동일한 값으로하여 여러개 배열 요소를 업데이트 이상이 더 많은 애플리케이션이있다 대량 작업이 사실에서 운동 "은 다수의 동작"으로 임의 연산 처리로 "일반"솔루션이며, 이후 이미, 그리고이 문제를 해결하는 가장 좋은 방법은 현재입니다.

  6. ==============================

    6.나는 아직도이 놀라 울뿐입니다 몽고에서 해결되지 않았습니다. 전체 몽고 하위 배열을 다룰 때 잘 될 것 같지 않습니다. 당신은 단순히 예를 들어 하위 배열을 셀 수 없다.

    나는 아직도이 놀라 울뿐입니다 몽고에서 해결되지 않았습니다. 전체 몽고 하위 배열을 다룰 때 잘 될 것 같지 않습니다. 당신은 단순히 예를 들어 하위 배열을 셀 수 없다.

    나는 하비에르 최초의 솔루션을 사용했다. 루프를 통해 다음 이벤트에 배열을 읽고 설정 특급을 구축 :

    var set = {}, i, l;
    for(i=0,l=events.length;i<l;i++) {
      if(events[i].profile == 10) {
        set['events.' + i + '.handled'] = 0;
      }
    }
    
    .update(objId, {$set:set});
    

    이것은 조건부 테스트 콜백을 사용하여 함수로 추상화 될 수있다

  7. ==============================

    7.나는 C # 3.6의 최신 드라이버를 사용하여이에 대한 해결책을 찾고 여기에 내가 결국에 정착 수정의 있었어요. 여기에 사용되는 키 "$ []"MongoDB에 따른 버전 3.6의 새로운된다. 자세한 내용은 https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up.S []를 참조하십시오.

    나는 C # 3.6의 최신 드라이버를 사용하여이에 대한 해결책을 찾고 여기에 내가 결국에 정착 수정의 있었어요. 여기에 사용되는 키 "$ []"MongoDB에 따른 버전 3.6의 새로운된다. 자세한 내용은 https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up.S []를 참조하십시오.

    여기 코드는 :

    {
       var filter = Builders<Scene>.Filter.Where(i => i.ID != null);
       var update = Builders<Scene>.Update.Unset("area.$[].discoveredBy");
       var result = collection.UpdateMany(filter, update, new UpdateOptions { IsUpsert = true});
    }
    

    더 컨텍스트가 여기 내 원래의 게시물을 참조하십시오 : MongoDB를 C #을 드라이버를 사용하는 모든 문서에서 배열 요소를 제거

  8. ==============================

    8.나는 다음과 작업 벌금을 시도했다.

    나는 다음과 작업 벌금을 시도했다.

    .update({'events.profile': 10}, { '$set': {'events.$.handled': 0 }},{ safe: true, multi:true }, callback function);
    

    nodejs 경우 // 콜백 함수

  9. ==============================

    9.스레드는 아주 오래된,하지만 난 따라서 새로운 솔루션을 제공 여기에 해답을 찾고왔다.

    스레드는 아주 오래된,하지만 난 따라서 새로운 솔루션을 제공 여기에 해답을 찾고왔다.

    MongoDB의 버전 3.6, 이는 어레이 내의 모든 아이템을 업데이트하는 위치 연산자를 사용하는 것이 가능하다. 여기에 공식 문서를 참조하십시오.

    문제는 여기에 요청에 대해 다음 쿼리가 작동합니다. 또한 자바 MongoDB를 드라이버를 확인하고이를 성공적으로 작동합니다.

    .update(   // or updateMany directly, removing the flag for 'multi'
       {"events.profile":10},
       {$set:{"events.$[].handled":0}},  // notice the empty brackets after '$' opearor
       false,
       true
    )
    

    이 나 같은 사람을 도움이되기를 바랍니다.

  10. ==============================

    10.사실, 명령 저장은 문서 클래스의 인스턴스입니다. 그 방법과 특성을 많이 가지고 있어요. 당신은 작업 부하를 줄이기 위해 린 () 함수를 사용할 수 있습니다. 여기를 참조하십시오. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

    사실, 명령 저장은 문서 클래스의 인스턴스입니다. 그 방법과 특성을 많이 가지고 있어요. 당신은 작업 부하를 줄이기 위해 린 () 함수를 사용할 수 있습니다. 여기를 참조하십시오. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

    동일한 시간에 저장 다중와의 충돌 데이터를 만들 것입니다 저장 기능의 또 다른 문제. Model.Update는 지속적으로 데이터를 만들 것입니다. 그래서 문서의 배열에 여러 항목을 업데이트합니다. 나는 그에서 몽구스를 사용하여 친숙한 프로그래밍 언어를 사용하여이 같은 시도 :

    User.findOne({'_id': '4d2d8deff4e6c1d71fc29a07'}).lean().exec()
      .then(usr =>{
        if(!usr)  return
        usr.events.forEach( e => {
          if(e && e.profile==10 ) e.handled = 0
        })
        User.findOneAndUpdate(
          {'_id': '4d2d8deff4e6c1d71fc29a07'},
          {$set: {events: usr.events}},
          {new: true}
        ).lean().exec().then(updatedUsr => console.log(updatedUsr))
    })
    
  11. ==============================

    11.$ [] 오퍼레이터가 선택한 모든 ..You 중첩 배열은 모든 어레이 업데이트 할 항목 '[$를]

    $ [] 오퍼레이터가 선택한 모든 ..You 중첩 배열은 모든 어레이 업데이트 할 항목 '[$를]

    .update({"events.profile":10},{$set:{"events.$[].handled":0}},false,true)
    

    참고

  12. ==============================

    12.이 스레드 제안 사용 $의 일부 답변 [] 잘못 양해하여 주시기 바랍니다.

    이 스레드 제안 사용 $의 일부 답변 [] 잘못 양해하여 주시기 바랍니다.

    db.collection.update(
       {"events.profile":10},
       {$set:{"events.$[].handled":0}},
       {multi:true}
    )
    

    상기 코드는 상관없이 "프로파일"의 값을 "이벤트"어레이의 모든 요소를 ​​0 "처리"업데이트한다. 쿼리 { "events.profile": 10} 전체 문서, 배열이 아닌 문서를 필터링 만입니다. 이 경우는 닐 룬의 대답이 정확한지 있도록 배열 항목의 조건을 지정하는 arrayFilters와 $ [ELEM]를 사용하는 것이 필수입니다.

  13. ==============================

    13.몽고 DB에서 여러 문서에 업데이트 배열 필드.

    몽고 DB에서 여러 문서에 업데이트 배열 필드.

    $ 풀 또는 MongoDB의에서 업데이트 배열 요소에 대한 업데이트를 많은 쿼리 $ 푸시를 사용합니다.

    Notification.updateMany(
        { "_id": { $in: req.body.notificationIds } },
        {
            $pull: { "receiversId": req.body.userId }
        }, function (err) {
            if (err) {
                res.status(500).json({ "msg": err });
            } else {
                res.status(200).json({
                    "msg": "Notification Deleted Successfully."
                });
            }
        });
    
  14. ==============================

    14.난 그냥 나를 위해 일한와 매우 간단 다른 솔루션을 추가하고 싶었다. 여기 태그 (문자열)의 단지 배열이다 그래서 "변경"을 "테스트"라는 태그를 업데이트하려면, 바로이 작업을 수행 :

    난 그냥 나를 위해 일한와 매우 간단 다른 솔루션을 추가하고 싶었다. 여기 태그 (문자열)의 단지 배열이다 그래서 "변경"을 "테스트"라는 태그를 업데이트하려면, 바로이 작업을 수행 :

    myDocuments.find({tags: "test" }, {fields: {_id: 1}}).forEach(function (doc) {
        myDocuments.update(
            {_id: doc._id, tags: "test"}, 
            {$set:{'tags.$': "changed"}});
        });
    
  15. from https://stackoverflow.com/questions/4669178/how-to-update-multiple-array-elements-in-mongodb by cc-by-sa and MIT license