복붙노트

[MONGODB] 어레이 내부 MongoDB를 업데이트 중첩 배열 [중복]

MONGODB

어레이 내부 MongoDB를 업데이트 중첩 배열 [중복]

나는 다음과 같은 MongoDB의 문서 구조를 가지고 :

[
    {
        "_id": "04",
        "name": "test service 4",
        "id": "04",
        "version": "0.0.1",
        "title": "testing",
        "description": "test",
        "protocol": "test",
        "operations": [
            {
                "_id": "99",
                "oName": "test op 52222222222",
                "sid": "04",
                "name": "test op 52222222222",
                "oid": "99",
                "description": "testing",
                "returntype": "test",
                "parameters": [
                    {
                        "oName": "Param1",
                        "name": "Param1",
                        "pid": "011",
                        "type": "582",
                        "description": "testing",
                        "value": ""
                    },
                    {
                        "oName": "Param2",
                        "name": "Param2",
                        "pid": "012",
                        "type": "58222",
                        "description": "testing",
                        "value": ""
                    }
                ]
            }
        ]
    }
]

그것이 작동하지 않는 매개 변수에 나는 작업에 업데이트 필드를 위해 $ elemMatch를 사용할 수 있었다, 그러나 나는 같은 일을하려고 할 때 (수정)했다. 나는 그 pid로를 찾는 특정 매개 변수를 성공적으로 업데이트 필드에 수 있도록하기 위해 노력하고 조사해야하는지 다른 방법 궁금 해서요.

나는 현재이이 같은 모습을 작동하지 않습니다 업데이트 코드 :

var oid = req.params.operations;
var pid = req.params.parameters;

collection.update({"parameters":{"$elemMatch": {"pid": pid}}},{"$set": {"parameters.$.name":req.body.name, "parameters.$.description": req.body.description,"parameters.$.oName": req.body.oName,"parameters.$.type": req.body.type} }, function(err, result) {
        if (err) {
            console.log('Error updating service: ' + err);
            res.send({'error':'An error has occurred'});
        } else {
            // console.log('' + result + ' document(s) updated');
            res.send(result);
        }
    });

해결법

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

    1.위의 MongoDB를 3.6로 \ 당신이 위치 필터링 $를 사용하여 중첩 된 배열을 업데이트 할 수있는 새로운 기능을 제공 [<식별자> \] 구문 업데이트 문에 arrayFilters을 통해 서로 다른 조건을 특정 요소를 일치 적용하기 위하여 :

    위의 MongoDB를 3.6로 \ 당신이 위치 필터링 $를 사용하여 중첩 된 배열을 업데이트 할 수있는 새로운 기능을 제공 [<식별자> \] 구문 업데이트 문에 arrayFilters을 통해 서로 다른 조건을 특정 요소를 일치 적용하기 위하여 :

    const { oid, pid } = req.params;
    const { name, oName, description, type } = req.body; 
    
    collection.update(
        {
            "_id": 1,
            "operations": {
                "$elemMatch": {
                    oid, "parameters.pid": pid
                }
            }
        },
        { "$set": { 
            "operations.$[outer].parameters.$[inner].name": name,
            "operations.$[outer].parameters.$[inner].description": description,
            "operations.$[outer].parameters.$[inner].oName": oName,
            "operations.$[outer].parameters.$[inner].type": type 
        } },
        { "arrayFilters": [
            { "outer.oid": oid },
            { "inner.pid": pid }
        ] }, (err, result) => {
        if (err) {
            console.log('Error updating service: ' + err);
            res.send({'error':'An error has occurred'});
        } else {
            // console.log('' + result + ' document(s) updated');
            res.send(result);
        }
    });
    

    로 @wdberkeley 그의 주석에서 언급 한 :

    나는 위의에 동의하고 MongoDB를 엔진은 여러 위치 연산자 (중첩 된 배열을 업데이트 할 위치 $ 연산자의 다중 사용을 참조하십시오)를 지원하지 않는 스키마를 다시 설계하는 것이 좋습니다

    그러나 매개 변수가 다음 업데이트 쿼리가 될 것입니다 사전에 업데이트 할 객체가 작업 배열의 인덱스를 알고있는 경우 :

    db.collection.update(
        {
            "_id" : "04", 
            "operations.parameters.pid": "011"
        }, 
        {
            "$set": { 
                "operations.0.parameters.$.name": "foo",
                "operations.0.parameters.$.description": "bar", 
                "operations.0.parameters.$.type": "foo" 
            }
        }
    )
    

    편집하다:

    그에 따라 수정 한 다음 객체에 대한 인덱스를 얻을 수 있도록하고 것, 즉 비행 뭔가에 $ 설정 조건을 생성하고 싶은 경우에, 맵리 듀스를 사용하는 것이 좋습니다.

    현재이 집계 프레임 워크를 사용하지 않을 수있을 것으로 보인다. 그것에 연결된 해결되지 않은 개방 JIRA 문제가 있습니다. 그러나, 해결 방법은 맵리 듀스 가능합니다. 맵리 듀스와 기본 개념은 그것의 쿼리 언어로 자바 스크립트를 사용하지만이 집계 프레임 워크에 비해 상당히 느린 경향 및 실시간 데이터 분석을 위해 사용해서는 안된다는 것입니다.

    당신의 맵리 듀스 작업, 당신은 몇 가지 단계가 매핑 단계, 즉 정의해야합니다 (컬렉션에있는 모든 문서에 작업을 매핑하고 작동이 중 아무것도하지 않고 또는 키와 일부 개체를 내고 값을 예상 할 수 있습니다) (단계를 감소 방출되는 값의리스트를 취하고) 단일 요소로 감소시킨다.

    지도 단계를 들어, 이상적으로 컬렉션에있는 모든 문서 얻고 싶은 것, 각 작업 배열 필드에 대한 인덱스와 다른 키 $ 세트 키를 포함하는.

    귀하의 감소 단계 (아무것도 안하는) 단순히 VAR 감소 = 함수 () {}로 정의 된 함수가 될 것이다;

    당신의 맵리 듀스 작업의 마지막 단계는 다음 $ 세트 조건 필드와 함께 방출 된 작업 배열 개체를 포함하는 분리 수거 작업을 생성합니다. 원래 수집에 맵리 듀스 작업을 실행할 때이 컬렉션은 주기적으로 업데이트 할 수 있습니다. 전체적으로이 맵리 듀스 방법은 같을 것이다 :

    var map = function(){
        for(var i = 0; i < this.operations.length; i++){
            emit( 
                {
                    "_id": this._id, 
                    "index": i 
                }, 
                {
                    "index": i, 
                    "operations": this.operations[i],            
                    "update": {
                        "name": "operations." + i.toString() + ".parameters.$.name",
                        "description": "operations." + i.toString() + ".parameters.$.description",
                        "type": "operations." + i.toString() + ".parameters.$.type"
                    }                    
                }
            );
        }
    };
    
    var reduce = function(){};
    
    db.collection.mapReduce(
        map,
        reduce,
        {
            "out": {
                "replace": "operations"
            }
        }
    );
    

    맵리 듀스 작업의 출력 수집 작업을 조회하는 것은 일반적으로 당신에게 결과를 줄 것이다 :

    db.operations.findOne()
    

    산출:

    {
        "_id" : {
            "_id" : "03",
            "index" : 0
        },
        "value" : {
            "index" : 0,
            "operations" : {
                "_id" : "96",
                "oName" : "test op 52222222222",
                "sid" : "04",
                "name" : "test op 52222222222",
                "oid" : "99",
                "description" : "testing",
                "returntype" : "test",
                "parameters" : [ 
                    {
                        "oName" : "Param1",
                        "name" : "foo",
                        "pid" : "011",
                        "type" : "foo",
                        "description" : "bar",
                        "value" : ""
                    }, 
                    {
                        "oName" : "Param2",
                        "name" : "Param2",
                        "pid" : "012",
                        "type" : "58222",
                        "description" : "testing",
                        "value" : ""
                    }
                ]
            },
            "update" : {
                "name" : "operations.0.parameters.$.name",
                "description" : "operations.0.parameters.$.description",
                "type" : "operations.0.parameters.$.type"
            }
        }
    }
    

    그런 다음 반복하고 그에 따라 컬렉션을 업데이트 할 db.operations.find () 메소드에서 커서를 사용할 수 있습니다 :

    var oid = req.params.operations;
    var pid = req.params.parameters;
    var cur = db.operations.find({"_id._id": oid, "value.operations.parameters.pid": pid });
    
    // Iterate through results and update using the update query object set dynamically by using the array-index syntax.
    while (cur.hasNext()) {
        var doc = cur.next();
        var update = { "$set": {} };
        // set the update query object
        update["$set"][doc.value.update.name] = req.body.name;
        update["$set"][doc.value.update.description] = req.body.description;
        update["$set"][doc.value.update.type] = req.body.type;
    
        db.collection.update(
            {
                "_id" : oid, 
                "operations.parameters.pid": pid
            }, 
            update 
        );
    };
    
  2. ==============================

    2.가 자주 변경되는 데이터 인 경우, 당신은 구조를 평평하지 않는 것을에서 많은 변화 데이터를 분리해야한다.

    가 자주 변경되는 데이터 인 경우, 당신은 구조를 평평하지 않는 것을에서 많은 변화 데이터를 분리해야한다.

    가 자주 변경되지 않는 데이터이며, 전체 데이터 객체가없는 대규모의 경우, 단지 객체의 클라이언트 측을 수정하고 전체 개체를 업데이트합니다.

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

    3.우리는 (ⅰ) 외부 배열의 인덱스를 찾으려고 할 것이다 내부 배열 (J) 다음 업데이트

    우리는 (ⅰ) 외부 배열의 인덱스를 찾으려고 할 것이다 내부 배열 (J) 다음 업데이트

    collection.findById (04) 그 때는 (결과 => {     대해 (ⅰ = 0하자 나는 res.json (dbModel))                 }             }         }     } })

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

    4.몽고 버전부터는 3.6이 업데이트 중첩 된 배열에 $ []과 연계 $ []를 사용할 수 있습니다

    몽고 버전부터는 3.6이 업데이트 중첩 된 배열에 $ []과 연계 $ []를 사용할 수 있습니다

    https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#position-nested-arrays-filtered

  5. from https://stackoverflow.com/questions/29634150/updating-nested-array-inside-array-mongodb by cc-by-sa and MIT license