복붙노트

[MONGODB] 어떻게하여 MongoDB에서 배열에서 항목의 인스턴스를 당겨?

MONGODB

어떻게하여 MongoDB에서 배열에서 항목의 인스턴스를 당겨?

문서에 따르면 :

값의 첫 번째 인스턴스를 제거 할 수있는 옵션이 있습니까? 예를 들면 :

var array = ["bird","tiger","bird","horse"]

어떻게 최초의 "새"가 업데이트 호출에서 직접 제거 할 수 있습니까?

해결법

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

    1.당신이 $ 풀 운영자가 정확히 않는다는 점에서 올바른 그래서 어떤 문서가의 인수가 사실상 제거 할 수있는 요소를 일치시키기 위해 사용되는 "쿼리"인 것을 말한다.

    당신이 $ 풀 운영자가 정확히 않는다는 점에서 올바른 그래서 어떤 문서가의 인수가 사실상 제거 할 수있는 요소를 일치시키기 위해 사용되는 "쿼리"인 것을 말한다.

    배열의 내용이 항상 "최초의"위치에있는 요소가 일어난 경우 다음 $ 연산자는 첫 번째 요소 그 사실 삭제에서와 팝업 표시한다.

    기본 노드 드라이버 :

    collection.findOneAndUpdate(
        { "array.0": "bird" },       // "array.0" is matching the value of the "first" element 
        { "$pop": { "array": -1 } },
        { "returnOriginal": false },
        function(err,doc) {
    
        }
    );
    

    몽구스으로 수정 된 문서를 반환하는 인수는 다르다 :

    MyModel.findOneAndUpdate(
        { "array.0": "bird" },
        { "$pop": { "array": -1 } },
        { "new": true },
        function(err,doc) {
    
        }
    );
    

    제거하려면 "첫 번째"항목의 배열 위치를 알 수없는 경우 그러나 어느 쪽도 많이 사용되지 않습니다.

    여기에 일반적인 접근을 위해 당신은 "이"업데이트, 첫 번째 항목을 일치하고 독특한 무언가로 대체 한 것을 제거 할 필요는 실제로 두 번째는 수정 된 항목을 제거합니다.

    이 반환 된 문서를 요청 간단한 업데이트를 적용 아니라면 훨씬 더 간단하고, 또한 문서에서 일괄 적으로 수행 할 수도 있습니다. 그것은 또한 당신의 전화를 중첩 방지하기 위해 async.series 같은 것을 사용하는 데 도움이 :

    async.series(
        [
            function(callback) {
                collection.update(
                    { "array": "bird" },
                    { "$unset": { "array.$": "" } },
                    { "multi": true }
                    callback
                );
            },
           function(callback) {
               collection.update(
                    { "array": null },
                    { "$pull": { "array": null } },
                    { "multi": true }
                    callback
               );
           }
        ],
        function(err) {
           // comes here when finished or on error   
        }
    );
    

    그래서 위치 $ 연산자 여기 설정 해제 $를 사용하여 "첫 번째"항목이 null로 변경 될 수 있습니다. 그리고 $ 풀과 이후의 쿼리는 단지 배열에 null 항목을 제거합니다.

    즉, 배열에서 안전하게 값의 "첫 번째"발생을 제거하는 방법이다. 그 배열이 같은 생각은 또 다른 질문입니다 하나 이상의 값이 포함되어 있는지 여부를 확인합니다.

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

    2.여기에 다른 대답은 일반적인 접근 방식은 여기에 널 (null) 값을 생성하기 위해 일치하는 배열 요소를 해제 $하는 다음 $ 배열에서 바로 널 (null) 값을 끌어 것이 참으로 올바른 반면에 더 나은 방법이 있다는 지적이의 가치 현대 MongoDB의 버전이를 구현합니다.

    여기에 다른 대답은 일반적인 접근 방식은 여기에 널 (null) 값을 생성하기 위해 일치하는 배열 요소를 해제 $하는 다음 $ 배열에서 바로 널 (null) 값을 끌어 것이 참으로 올바른 반면에 더 나은 방법이 있다는 지적이의 가치 현대 MongoDB의 버전이를 구현합니다.

    그 여러 업데이트가 하나의 응답 단일 요청으로 제출 할 수 있도록 권장 bulkWrite () 메소드를 통해 별도의 요청, 현대 MongoDB를 릴리스 지원 대량 작업과 같은 순서로 갱신 두 가지 작업을 제출하기 다른 경우로 :

        collection.bulkWrite(
          [
            { "updateOne": {
              "filter": { "array": "bird" },
              "update": {
                "$unset": { "array.$": "" }
              }
            }},
            { "updateOne": {
              "filter": { "array": null },
              "update": {
                "$pull": { "array": null }
              }
            }}
          ]
        );
    

    두 개의 요청으로 그것을 보여주는 답변으로 같은 일을하지만,이 시간은 단 하나입니다. 그것은 일반적으로 더 나은 접근 방식, 그래서 이것은 서버 통신 오버 헤드를 많이 절약 할 수 있습니다.

    MongoDB를 4.2의 출시와 함께, 집계 표현은 이제 MongoDB를 다양한 "갱신"작업에 사용할 수 있습니다. 이 중 $의 addFields의 단일 파이프 라인 단계이다, $ 프로젝트 또는 $ replaceRoot (이 "업데이트"문을 논리적으로 읽을 수 있도록하기위한 것 $ addFields의 별칭입니다) 그리고 그것은 자신의 별명 $의 replaceWith의 $ 세트. 은 $ 편집하다 파이프 라인 단계는 어느 정도 여기에 적용됩니다. 기본적으로 "고쳐"문서를 반환하는 모든 파이프 라인 단계가 허용됩니다.

    collection.updateOne(
      { "array": "horse" },
      [
        { "$set": {
          "array": {
            "$concatArrays": [
              { "$slice": [ "$array", 0, { "$indexOfArray": [ "$array", "horse" ] }] },
              { "$slice": [
                "$array",
                { "$add": [{ "$indexOfArray": [ "$array", "horse" ] }, 1] },
                { "$size": "$array" }
              ]}
            ]
          }
        }}
      ]
    );
    

    이 경우에 사용되는 조작 함께 본질적 부분에 제 유사한 배열 요소 위에 새로운 배열 "스킵의"$ 슬라이스 $ indexOfArray 연산자를 구현하는 것이다. 논문 조각 제 유사한 요소의 새로운 배열의 존재를 반환하여 $ concatArrays 연산자로 결합된다.

    인 작업이 여전히 하나의 요청이 이제 단일 작업이며, 좀 덜 서버 오버 헤드가 발생 것이기 때문에 이것은 아마도 이제 더 효과적입니다.

    물론 유일한 캐치이 4.2 이전하여 MongoDB의 릴리스에서 지원되지 않는 것입니다. 반면에 bulkWrite ()는 새로운 API 구현 될 수 있지만 서버의 실제 기본 호출은 실제 "대량 API"호출을 구현하는 MongoDB를 2.6로 다시 적용됩니다, 심지어 그런데 이전 버전으로 다시 회귀 모든 핵심 드라이버 실제로이 방법을 구현한다.

    데모로, 여기에 두 가지 접근법의 목록입니다 :

    const { Schema } = mongoose = require('mongoose');
    
    const uri = 'mongodb://localhost:27017/test';
    const opts = { useNewUrlParser: true, useUnifiedTopology: true };
    
    mongoose.Promise = global.Promise;
    
    mongoose.set('debug', true);
    mongoose.set('useCreateIndex', true);
    mongoose.set('useFindAndModify', false);
    
    
    const arrayTestSchema = new Schema({
      array: [String]
    });
    
    const ArrayTest = mongoose.model('ArrayTest', arrayTestSchema);
    
    const array = ["bird", "tiger", "horse", "bird", "horse"];
    
    const log = data => console.log(JSON.stringify(data, undefined, 2));
    
    (async function() {
    
      try {
        const conn = await mongoose.connect(uri, opts);
    
        await Promise.all(
          Object.values(conn.models).map(m => m.deleteMany())
        );
    
        await ArrayTest.create({ array });
    
        // Use bulkWrite update
        await ArrayTest.bulkWrite(
          [
            { "updateOne": {
              "filter": { "array": "bird" },
              "update": {
                "$unset": { "array.$": "" }
              }
            }},
            { "updateOne": {
              "filter": { "array": null },
              "update": {
                "$pull": { "array": null }
              }
            }}
          ]
        );
    
        log({ bulkWriteResult: (await ArrayTest.findOne()) });
    
        // Use agggregation expression
        await ArrayTest.collection.updateOne(
          { "array": "horse" },
          [
            { "$set": {
              "array": {
                "$concatArrays": [
                  { "$slice": [ "$array", 0, { "$indexOfArray": [ "$array", "horse" ] }] },
                  { "$slice": [
                    "$array",
                    { "$add": [{ "$indexOfArray": [ "$array", "horse" ] }, 1] },
                    { "$size": "$array" }
                  ]}
                ]
              }
            }}
          ]
        );
    
        log({ aggregateWriteResult: (await ArrayTest.findOne()) });
    
      } catch (e) {
        console.error(e);
      } finally {
        mongoose.disconnect();
      }
    
    
    })();
    

    그리고 출력 :

    Mongoose: arraytests.deleteMany({}, {})
    Mongoose: arraytests.insertOne({ array: [ 'bird', 'tiger', 'horse', 'bird', 'horse' ], _id: ObjectId("5d8f509114b61a30519e81ab"), __v: 0 }, { session: null })
    Mongoose: arraytests.bulkWrite([ { updateOne: { filter: { array: 'bird' }, update: { '$unset': { 'array.$': '' } } } }, { updateOne: { filter: { array: null }, update: { '$pull': { array: null } } } } ], {})
    Mongoose: arraytests.findOne({}, { projection: {} })
    {
      "bulkWriteResult": {
        "array": [
          "tiger",
          "horse",
          "bird",
          "horse"
        ],
        "_id": "5d8f509114b61a30519e81ab",
        "__v": 0
      }
    }
    Mongoose: arraytests.updateOne({ array: 'horse' }, [ { '$set': { array: { '$concatArrays': [ { '$slice': [ '$array', 0, { '$indexOfArray': [ '$array', 'horse' ] } ] }, { '$slice': [ '$array', { '$add': [ { '$indexOfArray': [ '$array', 'horse' ] }, 1 ] }, { '$size': '$array' } ] } ] } } } ])
    Mongoose: arraytests.findOne({}, { projection: {} })
    {
      "aggregateWriteResult": {
        "array": [
          "tiger",
          "bird",
          "horse"
        ],
        "_id": "5d8f509114b61a30519e81ab",
        "__v": 0
      }
    }
    
  3. from https://stackoverflow.com/questions/32018889/how-to-pull-one-instance-of-an-item-in-an-array-in-mongodb by cc-by-sa and MIT license