복붙노트

[MONGODB] MongoDB를 업데이트 깊이 하위 문서를 중첩

MONGODB

MongoDB를 업데이트 깊이 하위 문서를 중첩

나는 깊게과 같이 중첩 된 문서의 구조를 가지고 :

{id: 1, 
 forecasts: [ { 
             forecast_id: 123, 
             name: "Forecast 1", 
             levels: [ 
                { level: "proven", 
                  configs: [
                            { 
                              config: "Custom 1",
                              variables: [{ x: 1, y:2, z:3}]
                            }, 
                            { 
                              config: "Custom 2",
                              variables: [{ x: 10, y:20, z:30}]
                            }, 
                    ]
                }, 
                { level: "likely", 
                  configs: [
                            { 
                              config: "Custom 1",
                              variables: [{ x: 1, y:2, z:3}]
                            }, 
                            { 
                              config: "Custom 2",
                              variables: [{ x: 10, y:20, z:30}]
                            }, 
                    ]
                }
            ]
        }, 
    ]

}

나는 새로운 설정, 같은 그 모습을 삽입 할 컬렉션을 업데이트하기 위해 노력하고있어 :

newdata =  {
  config: "Custom 1", 
  variables: [{ x: 111, y:2222, z:3333}]
}

나는 (파이썬) 몽고의이 같은 노력하고있어 :

db.myCollection.update({"id": 1, 
                        "forecasts.forecast-id": 123, 
                        "forecasts.levels.level": "proven", 
                        "forecasts.levels.configs.config": "Custom 1"
                         },
                         {"$set": {"forecasts.$.levels.$.configs.$": newData}}
                      )

그래도 오류 "배열을 포함하는 해당 쿼리 필드없이 위치 연산자를 적용 할 수 없습니다"얻고있다. 몽고에서이 작업을 수행하는 적절한 방법은 무엇입니까? 이 몽고 v2.4.1입니다.

해결법

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

    1.당신이 나머지 숫자 값을 사용할 필요가 불행하게도, 당신은 더 키 당 한 번 이상 $ 연산자를 사용할 수 없습니다. 마찬가지로 :

    당신이 나머지 숫자 값을 사용할 필요가 불행하게도, 당신은 더 키 당 한 번 이상 $ 연산자를 사용할 수 없습니다. 마찬가지로 :

    db.myCollection.update({
        "id": 1, 
        "forecasts.forecast-id": 123, 
        "forecasts.levels.level": "proven", 
        "forecasts.levels.configs.config": "Custom 1"
      },
      {"$set": {"forecasts.$.levels.0.configs.0": newData}}
    )
    

    중첩 된 배열을 업데이트하여 MongoDB의 지원이 좋지 않습니다. 자주 데이터를 업데이트하고, 대신 여러 컬렉션을 사용하여 고려할 필요가있는 경우 사용을 피하는 길 이죠 가장 잘 그래서.

    하나의 가능성 : 메이크업은 자신의 컬렉션을 예측하고이 레벨 값의 고정 세트, 메이크업 수준이 가정 대신 배열의 객체 :

    {
      _id: 123,
      parentId: 1,
      name: "Forecast 1", 
      levels: {
        proven: { 
          configs: [
            { 
              config: "Custom 1",
              variables: [{ x: 1, y:2, z:3}]
            }, 
            { 
              config: "Custom 2",
              variables: [{ x: 10, y:20, z:30}]
            }, 
          ]
        },
        likely: {
          configs: [
            { 
              config: "Custom 1",
              variables: [{ x: 1, y:2, z:3}]
            }, 
            { 
              config: "Custom 2",
              variables: [{ x: 10, y:20, z:30}]
            }, 
          ]
        }
      }
    }
    

    그럼 당신은 사용하여 업데이트 할 수 있습니다 :

    db.myCollection.update({
        _id: 123,
        'levels.proven.configs.config': 'Custom 1'
      },
      { $set: { 'levels.proven.configs.$': newData }}
    )
    
  2. ==============================

    2.몽구스를 사용하여 그것을 해결하기 위해 관리 :

    몽구스를 사용하여 그것을 해결하기 위해 관리 :

    당신이 알아야 할 모든 '(각 하위 문서에 대해'_ID 만들기 자동으로 몽구스) 체인의 하위 문서의 모든 _id의 '입니다.

    예를 들어 -

      SchemaName.findById(_id, function (e, data) {
          if (e) console.log(e);
          data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;
    
          // or if you want to change more then one field -
          //=> var t = data.sub1.id(_id1).sub2.id(_id2);
          //=> t.field = req.body.something;
    
          data.save();
      });
    

    더 몽구스 문서의 하위 문서 _id 방법에 대해.

    설명 : _id는 SUB2에 대한 SUB1과 _id2에 대한 스키마 명, _id1입니다 - 당신이 그런 체인 유지할 수 있습니다.

    * 당신은 findById 메소드의 방법을 사용할 필요가 없습니다,하지만 당신은 '_id의 어차피의 나머지 부분을 알 필요로 나를 가장 편리한 것입니다.

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

    3.MongoDB를 버전 3.5.2 및 이후 버전에서이 문제를 해결하기 위해 ArrayFilters을 발표했다.

    MongoDB를 버전 3.5.2 및 이후 버전에서이 문제를 해결하기 위해 ArrayFilters을 발표했다.

    [https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-an-array-update-operations][1]

    다음과 같이하자는 스키마 디자인을 말한다 :

    var ProfileSchema = new Schema({
        name: String,
        albums: [{
            tour_name: String,
            images: [{
                title: String,
                image: String
            }]
        }]
    });
    

    그리고 문서는이 같은 모습을 만들어 :

    {
       "_id": "1",
       "albums": [{
                "images": [
                   {
                      "title": "t1",
                      "url": "url1"
                   },
                   {
                      "title": "t2",
                      "url": "url2"
                   }
                ],
                "tour_name": "london-trip"
             },
             {
                "images": [.........]: 
             }]
    }
    

    나는 이미지의 "URL"을 업데이트 할 말. 주어 - "문서 ID", "tour_name"와 "제목"

    이 업데이트를 쿼리 :

    Profiles.update({_id : req.body.id},
        {
            $set: {
    
                'albums.$[i].images.$[j].title': req.body.new_name
            }
        },
        {
            arrayFilters: [
                {
                    "i.tour_name": req.body.tour_name, "j.image": req.body.new_name   // tour_name -  current tour name,  new_name - new tour name 
                }]
        })
        .then(function (resp) {
            console.log(resp)
            res.json({status: 'success', resp});
        }).catch(function (err) {
        console.log(err);
        res.status(500).json('Failed');
    })
    
  4. ==============================

    4.이 MongoDB의 아주 오래 된 버그

    이 MongoDB의 아주 오래 된 버그

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

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

    5.MongoDB를이에 대한 좋은 메커니즘을 제공하기 위해 표시되지 않습니다 방법을 감안할 때, 나는 그것이 신중한 단순히 .findOne을 (...)를 사용하여 몽고의 컬렉션에서 요소를 추출에 몽구스를 사용하여 발견의 관련 하위 요소에 대한 루프 검색을 실행 , JSON은 다음 Schema.markModified을 할 것을 수정 (예를 들어 OBJECTID에 의해 추구) ( 'your.subdocument'); Schema.save (); 아마 효율적 아니지만, 그것은 매우 간단하고 잘 작동합니다.

    MongoDB를이에 대한 좋은 메커니즘을 제공하기 위해 표시되지 않습니다 방법을 감안할 때, 나는 그것이 신중한 단순히 .findOne을 (...)를 사용하여 몽고의 컬렉션에서 요소를 추출에 몽구스를 사용하여 발견의 관련 하위 요소에 대한 루프 검색을 실행 , JSON은 다음 Schema.markModified을 할 것을 수정 (예를 들어 OBJECTID에 의해 추구) ( 'your.subdocument'); Schema.save (); 아마 효율적 아니지만, 그것은 매우 간단하고 잘 작동합니다.

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

    6.그것은 고정입니다. https://jira.mongodb.org/browse/SERVER-831

    그것은 고정입니다. https://jira.mongodb.org/browse/SERVER-831

    그러나이 기능은 MongoDB를 3.5.12 개발 버전을 사용할 시작이다.

    이 질문에 8 월 (11) 2013 질문과 2017 년 8 월 11 일에 해결 될 것 참고 :

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

    7.오늘 문제의 같은 종류에 직면하였고, 구글에 탐험의 많은 후 / 유래 / github에, 나는 생각 된 arrayFilters은이 문제에 대한 최적의 솔루션입니다. 어떤 몽고 3.6 이상으로 작동합니다. 이 링크는 결국 내 일을 저장 : https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html

    오늘 문제의 같은 종류에 직면하였고, 구글에 탐험의 많은 후 / 유래 / github에, 나는 생각 된 arrayFilters은이 문제에 대한 최적의 솔루션입니다. 어떤 몽고 3.6 이상으로 작동합니다. 이 링크는 결국 내 일을 저장 : https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html

    const OrganizationInformationSchema = mongoose.Schema({
    user: {
        _id: String,
        name: String
    },
    organizations: [{
        name: {
            type: String,
            unique: true,
            sparse: true
        },
        rosters: [{
            name: {
                type: String
            },
            designation: {
                type: String
            }
        }]
    }]
    }, {
        timestamps: true
    });
    

    그리고 지정된 ID의 명단의 이름을 업데이트 명시 적으로 몽구스를 사용하여.

    const mongoose = require('mongoose');
    const ControllerModel = require('../models/organizations.model.js');
    module.exports = {
    // Find one record from database and update.
    findOneRosterAndUpdate: (req, res, next) => {
        ControllerModel.updateOne({}, {
            $set: {
                "organizations.$[].rosters.$[i].name": req.body.name
            }
        }, {
            arrayFilters: [
                { "i._id": mongoose.Types.ObjectId(req.params.id) }
            ]
        }).then(response => {
            res.send(response);
        }).catch(err => {
            res.status(500).send({
                message: "Failed! record cannot be updated.",
                err
            });
        });
    }
    }
    
  8. ==============================

    8.내 교훈을 공유 배웠습니다. 내가 중첩 배열 항목을 업데이트 할 필요가 어디 최근 같은 요구 사항에 직면했다. 다음과 같이 내 구조는

    내 교훈을 공유 배웠습니다. 내가 중첩 배열 항목을 업데이트 할 필요가 어디 최근 같은 요구 사항에 직면했다. 다음과 같이 내 구조는

      {
        "main": {
          "id": "ID_001",
          "name": "Fred flinstone Inc"
        },
        "types": [
          {
            "typeId": "TYPE1",
            "locations": [
              {
                "name": "Sydney",
                "units": [
                  {
                    "unitId": "PHG_BTG1"
                  }
                ]
              },
              {
                "name": "Brisbane",
                "units": [
                  {
                    "unitId": "PHG_KTN1"
                  },
                  {
                    "unitId": "PHG_KTN2"
                  }
                ]
              }
            ]
          }
        ]
      }
    

    내 요구 사항은 특정 단위 []에 일부 필드를 추가하는 것입니다. 내 솔루션은 중첩 된 배열 항목의 인덱스를 찾을 수 처음이다 (foundUnitIdx 말) 내가 사용하는 두 가지 기술은

    이 다른 사람에게 도움이되기를 바랍니다. :)

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

    9.Okkk.we는 mongodb.this 우리의 중첩 된 하위 문서는 우리의 스키마입니다 업데이트 할 수 있습니다.

    Okkk.we는 mongodb.this 우리의 중첩 된 하위 문서는 우리의 스키마입니다 업데이트 할 수 있습니다.

    var Post = new mongoose.Schema({
        name:String,
        post:[{
            like:String,
            comment:[{
                date:String,
                username:String,
                detail:{
                    time:String,
                    day:String
                }
            }]
        }]
    })
    

    이 스키마에 대한 솔루션

      Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
        {$set:{"post.$.comment.0.detail.time":"aajtk"}},
              function(err,data){
    //data is updated
    })
    
  10. ==============================

    10.쉬운 솔루션을위한 MongoDB를 3.2 이상 https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/

    쉬운 솔루션을위한 MongoDB를 3.2 이상 https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/

    나는 비슷한 상황이 있고 이런 식으로 해결. 나는 몽구스를 사용했지만, 여전히 바닐라 MongoDB를 작동한다. 누군가에게 유용 바랍니다.

    const MyModel = require('./model.js')
    const query = {id: 1}
    
    // First get the doc
    MyModel.findOne(query, (error, doc) => {
    
        // Do some mutations
        doc.foo.bar.etc = 'some new value'
    
        // Pass in the mutated doc and replace
        MyModel.replaceOne(query, doc, (error, newDoc) => {
             console.log('It worked!')
        })
    }
    

    사용 사례에 따라) (초기 findOne을 생략 할 수있을 것

  11. from https://stackoverflow.com/questions/18173482/mongodb-update-deeply-nested-subdocument by cc-by-sa and MIT license