2016-08-08 2 views
4

I는 다음과 같이 문서를 작성 모음이 있습니다가장 효율적인 방법

{ 
    data: 55, 
    version: "0.0.42-test" 
} 

:

{ 
    data: 11, 
    version: "0.0.32" 
} 

을하고 일부는 test 접미사 version에이 version 필드에는 다른 값이 있지만 항상 패턴 : 0.0.XXX을 준수합니다. 이러한 문서와 컬렉션에 의해 사용되는

{ 
    data: 55, 
    version: -42 
} 

: -

{ 
    data: 11, 
    version: 32 
} 

및 (version 부정적인해야 테스트 문서의 경우) 접미사 버전 :이처럼 보이도록 모든 문서를 업데이트 할 것 우리의 중요한 시스템은 데이터를 업데이트하는 동안 꺼야하므로 가능한 빨리 업데이트/변경을 원합니다. 이 컬렉션에는 약 66_000_000 개의 문서가 있으며 크기는 약 100GB입니다.

가장 효율적인 mongodb 작업 유형은 무엇입니까?

+0

에서 쇼와 지금은 사용되지 않는 Bulk() API과 관련된 방법을 사용해야합니다. 32 ". 사실, 그것은 전혀 문자열이 아닙니다. 조피. –

+0

문제의 핵심은 하위 문자열을 가져 오는 것입니다. 더 나은 타이틀을 찾는 데 저를 도와 줄 수 있습니까? –

답변

4

이를위한 가장 효율적인 방법이 shown here은 다음 $let 변수 연산자를 사용하여 변수에 배열의 마지막 요소를 할당 우리의 문자열을 분할하는 $split 연산자를 사용하여 작성하고, 현재의 MongoDB의의 곧 출시에 $arrayElemAt 연산자.

다음으로 $switch 연산자를 사용하여 해당 변수에 대한 논리 조건 처리 또는 case 문을 수행합니다.

여기에 조건 값이 "test"을 포함하고 의 발현이 경우 우리는 해당 문자열을 분할하고 간단하게 새로 계산 된 배열과의 첫 번째 요소의 $concat enated 값을 반환하는 경우 true를 반환 $gt입니다 -. 조건이 false로 평가되면 변수 만 반환합니다.

물론 우리 사례 명세서에서는 "test"이없는 경우 -1을 반환하는 $indexOfCP을 사용합니다.

let cursor = db.collection.aggregate(
    [ 
     { "$project": { 
      "data": 1, 
      "version": { 
       "$let": { 
        "vars": { 
         "v": { 
          "$arrayElemAt": [ 
           { "$split": [ "$version", "." ] }, 
           -1 
          ] 
         } 
        }, 
        "in": { 
         "$switch": { 
          "branches": [ 
           { 
            "case": { 
             "$gt": [ 
              { "$indexOfCP": [ "$$v", "test" ] }, 
              -1 
             ] 
            }, 
            "then": { 
             "$concat": [ 
              "-", 
              "", 
              { "$arrayElemAt": [ 
               { "$split": [ "$$v", "-" ] }, 
               0 
              ]} 
             ] 
            } 
           } 
          ], 
          "default": "$$v" 
         } 
        } 
       } 
      } 
     }} 
    ] 
) 

집계 쿼리는 다음과 같은 것을 만들어 : 당신이 볼 수 있듯이

{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" } 
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" } 

, "버전"필드 데이터 문자열입니다. 해당 필드의 데이터 형식이 중요하지 않은 경우 $out 집계 파이프 라인 단계 연산자를 사용하여 결과를 새 컬렉션에 쓰거나 컬렉션을 바꿀 수 있습니다.

{ "out": "collection" } 

당신이 다음 부동 소수점 숫자에 데이터를 변환해야하는 경우, 유일한 방법은 MongoDB를 문자열의 정수를 제외하고 밖으로 상자의 형식 변환을 할 수있는 방법을 제공하지 않는 간단하기 때문에,이 작업을 수행하는 집계 Cursor 객체를 반복하고 parseFloat 또는 Number을 사용하여 값을 변환 한 다음 최대 효율성을 위해 $set 연산자와 bulkWrite() 연산자를 사용하여 문서를 업데이트해야합니다.


집계 쿼리가 완벽하게 MongoDB를 3.2에서 MongoDB를 3.4 이상 우리의 최선의에서 작동하지만

let requests = []; 
cursor.forEach(doc => { 
    requests.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { 
       "$set": { 
        "data": doc.data, 
        "version": parseFloat(doc.version) 
       }, 
       "$unset": { "person": " " } 
      } 
     } 
    }); 
    if (requests.length === 1000) { 
     // Execute per 1000 ops and re-init 
     db.collection.bulkWrite(requests); 
     requests = []; 
    }} 
); 

// Clean up queues 
if(requests.length > 0) { 
    db.coll.bulkWrite(requests); 
} 

는 뒤로 bulkWrite() 방법 mapReduce입니다.

var results = db.collection.mapReduce(
    function() { 
     var v = this.version.split(".")[2]; 
     emit(this._id, v.indexOf("-") > -1 ? "-"+v.replace(/\D+/g, '') : v) 
    }, 
    function(key, value) {}, 
    { "out": { "inline": 1 } } 
)["results"]; 

results은 다음과 같다 : 여기에서

[ 
    { 
     "_id" : ObjectId("57a98773cbbd42a2156260d8"), 
     "value" : "32" 
    }, 
    { 
     "_id" : ObjectId("57a98773cbbd42a2156260d9"), 
     "value" : "-42" 
    } 
] 

당신이 문서를 업데이트 이전 .forEach 루프를 사용합니다.


MongoDB를 2.6에서 3.0으로 당신은 제목,`32` '0.0'의 하위 문자열이 __not__입니다에 대한 내 answer here.

관련 문제