복붙노트

[MONGODB] 일치하는 파이프 라인에서 문서의 집계 $ 조회 총 크기는 최대 문서 크기를 초과

MONGODB

일치하는 파이프 라인에서 문서의 집계 $ 조회 총 크기는 최대 문서 크기를 초과

나는 아주 간단 $를 조회 집계 쿼리 다음과 같은 :

{'$lookup':
 {'from': 'edge',
  'localField': 'gid',
  'foreignField': 'to',
  'as': 'from'}}

내가 충분히 문서와 일치에서이 프로그램을 실행할 때 나는 다음과 같은 오류가 발생합니다 :

Command failed with error 4568: 'Total size of documents in edge
matching { $match: { $and: [ { from: { $eq: "geneDatabase:hugo" }
}, {} ] } } exceeds maximum document size' on server

문서 실패의 모든 시도 횟수를 제한합니다. allowDiskUse : 사실은 아무것도하지 않는다. 에 커서를 보내는 것은 아무것도하지 않는다. 집계에 $ 제한에 추가하면 실패합니다.

이 어떻게 될 수 있을까?

그럼 난 다시 오류가 표시됩니다. 그 $ 일치와 $ 및 및 $ EQ는 어디에서 왔는가? 뒤에서 집계 파이프 라인이 다른 집단에 $ 조회 호출을 농업되어, 하나는 내가 함께에 대한 제한 또는 사용 커서를 제공 할 능력이 없다는 것을 자체에서 실행 ??

무슨 일이야?

해결법

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

    1.이전의 주석에서 설명한 바와 같이, 기본적으로 외부 컬렉션의 결과로부터 부모 문서 내의 타겟 "배열"생산 $ 검색을 수행 할 때, 그 어레이의 선택된 문서의 전체 크기를 초과하는 상위가 발생하기 때문에 에러가 발생 16메가바이트 BSON 제한.

    이전의 주석에서 설명한 바와 같이, 기본적으로 외부 컬렉션의 결과로부터 부모 문서 내의 타겟 "배열"생산 $ 검색을 수행 할 때, 그 어레이의 선택된 문서의 전체 크기를 초과하는 상위가 발생하기 때문에 에러가 발생 16메가바이트 BSON 제한.

    이에 대한 카운터는 즉시 $ 조회 파이프 라인 단계를 따르는 $를 해제하는 과정이다. 대신 부모의 어레이를 제조하는 결과 대신 유사한 모든 문서에 대해 각각 상위의 "복사본"이되도록이 사실 달라져 $ 룩업 동작한다.

    꽤 많은 단지 대신에 "별도의"파이프 라인 단계로 처리의, 긴장을 풀기 동작이 실제로 $ 조회 파이프 라인 작업 자체에 추가를 제외하고 $ 언 와인드의 일반적인 사용에는,있다. 이상적으로 당신은 또한 또한 또한 $ 조회에 추가 할에 일치하는 인수를 생성하는 $ 일치 조건과 $의 풀림을 따릅니다. 당신은 실제로 파이프 라인에 대한 설명 출력에서 ​​볼 수 있습니다.

    주제는 실제로 핵심 설명서에서 집계 파이프 라인 최적화의 섹션 (간략하게)가 적용됩니다

    베스트와 함께 시연 a를 16 메가 바이트 BSON 한도를 초과 "관련"문서를 작성하여 스트레스가 풋 서버 목록. BSON 제한 주위에 모두 휴식과 업무에 가능한 한 짧게으로 완료 :

    const MongoClient = require('mongodb').MongoClient;
    
    const uri = 'mongodb://localhost/test';
    
    function data(data) {
      console.log(JSON.stringify(data, undefined, 2))
    }
    
    (async function() {
    
      let db;
    
      try {
        db = await MongoClient.connect(uri);
    
        console.log('Cleaning....');
        // Clean data
        await Promise.all(
          ["source","edge"].map(c => db.collection(c).remove() )
        );
    
        console.log('Inserting...')
    
        await db.collection('edge').insertMany(
          Array(1000).fill(1).map((e,i) => ({ _id: i+1, gid: 1 }))
        );
        await db.collection('source').insert({ _id: 1 })
    
        console.log('Fattening up....');
        await db.collection('edge').updateMany(
          {},
          { $set: { data: "x".repeat(100000) } }
        );
    
        // The full pipeline. Failing test uses only the $lookup stage
        let pipeline = [
          { $lookup: {
            from: 'edge',
            localField: '_id',
            foreignField: 'gid',
            as: 'results'
          }},
          { $unwind: '$results' },
          { $match: { 'results._id': { $gte: 1, $lte: 5 } } },
          { $project: { 'results.data': 0 } },
          { $group: { _id: '$_id', results: { $push: '$results' } } }
        ];
    
        // List and iterate each test case
        let tests = [
          'Failing.. Size exceeded...',
          'Working.. Applied $unwind...',
          'Explain output...'
        ];
    
        for (let [idx, test] of Object.entries(tests)) {
          console.log(test);
    
          try {
            let currpipe = (( +idx === 0 ) ? pipeline.slice(0,1) : pipeline),
                options = (( +idx === tests.length-1 ) ? { explain: true } : {});
    
            await new Promise((end,error) => {
              let cursor = db.collection('source').aggregate(currpipe,options);
              for ( let [key, value] of Object.entries({ error, end, data }) )
                cursor.on(key,value);
            });
          } catch(e) {
            console.error(e);
          }
    
        }
    
      } catch(e) {
        console.error(e);
      } finally {
        db.close();
      }
    
    })();
    

    일부 초기 데이터를 삽입 한 후, 목록은 다음과 같은 오류와 함께 실패합니다 $ 조회로 구성된 단지 집계를 실행하려고합니다 :

    기본적으로 BSON 제한은 검색에 초과 당신에게 한 이야기이다.

    반면 다음 시도는 $ 긴장을 풀고 $ 일치하는 파이프 라인 단계를 추가

    출력 설명 :

      {
        "$lookup": {
          "from": "edge",
          "as": "results",
          "localField": "_id",
          "foreignField": "gid",
          "unwinding": {                        // $unwind now is unwinding
            "preserveNullAndEmptyArrays": false
          },
          "matching": {                         // $match now is matching
            "$and": [                           // and actually executed against 
              {                                 // the foreign collection
                "_id": {
                  "$gte": 1
                }
              },
              {
                "_id": {
                  "$lte": 5
                }
              }
            ]
          }
        }
      },
      // $unwind and $match stages removed
      {
        "$project": {
          "results": {
            "data": false
          }
        }
      },
      {
        "$group": {
          "_id": "$_id",
          "results": {
            "$push": "$results"
          }
        }
      }
    

    결과가 더 이상으로서 다음 BSON 제한을 초과 할 수없는 부모 문서에 배치되고 있지 때문에 물론 그 결과는 성공합니다.

    이것은 정말 언 와인드 만 $를 추가의 결과로 발생하지만, $ 일치는이 또한 $ 조회 단계로 전체적인 효과는 효과적인 방법으로 반환 "제한"결과 인 것이 추가 된 것을 보여주기 위해 예를 들어 추가 이 모든 $ 조회 작업에서 수행하고 이후 그 일치 이외의 다른 결과는 실제로 반환되지 않습니다.

    당신이 BSON 제한을 초과하고 $ 그룹을 원한다면 그들이 효과적으로 필터링 된 후 결과가되는 사실이다 "숨겨진 질의"에 의해, 배열 형식으로 백업 한 후 것이다 "참조 데이터"를 조회 할 수 있습니다 이런 식으로 구성하여 $ 룩업 의해 수행.

    노트 위의 모든 내용으로, BSON 제한은 위반 수없는 "하드"제한이하고 $ 언 와인드는 중간 단계로 필요한 이유는 일반적으로. 은 An $의 미덕 언 와인드 곳이 내용을 보존 할 수에 의해 "내부 조인"가 "좌 가입"고 제한 그러나이있다. 또한도 preserveNulAndEmptyArrays는 "합체"를 부정하는 것이며, 여전히 같은 BSON 제한 문제를 일으키는 그대로 배열을 둡니다.

    MongoDB를 3.6는 "서브 - 파이프 라인"발현 "로컬"및 "외부"키 대신에 사용될 수 있도록 $ 룩업 새로운 구문을 추가한다. 그래서 그 대신 증명으로 "합체"옵션을 사용하는만큼, 생성 된 배열도 제한을 위반하지 않는 한이 나타내는 것으로 전혀 일치와 가능성 "그대로"배열을 반환 파이프 라인에 조건을 넣어 수 있습니다 (A)의 "왼쪽 가입".

    새로운 표현은 다음과 같다 :

    { "$lookup": {
      "from": "edge",
      "let": { "gid": "$gid" },
      "pipeline": [
        { "$match": {
          "_id": { "$gte": 1, "$lte": 5 },
          "$expr": { "$eq": [ "$$gid", "$to" ] }
        }}          
      ],
      "as": "from"
    }}
    

    사실이 MongoDB를가 문을 구축하기 위해 3.6 사용 "내부적으로"$ expr에 있기 때문에 이전 구문 "내부적으로"하고있다 기본적으로 무엇을 할 것이다. 물론 차이는 $가 조회 실제로 실행되는 방식에는 "풀기"옵션 존재가없는 것입니다.

    어떤 문서가 실제로 "파이프 라인"표현의 결과로 생성되지 않으면 마스터 문서 내에서 대상 배열은 사실에 실제로 않습니다 "LEFT JOIN을"어떤없이 $ 조회의 정상적인 동작 될 것처럼 비어 있습니다 다른 옵션.

    그러나 MUST에 출력 배열은 상기 BSON 한계를 초과 작성되는 문서가 발생하지. 정말이 제한 또는 동일한 오류 조건 체류에 의한 "일치"내용이 지속될 것이라는 점을 보장하기 위해 당신에게 달려 그래서, 물론하지 않는 한 당신은 실제로는 "내부 조인"에 영향을 $ 언 와인드를 사용합니다.

  2. from https://stackoverflow.com/questions/45724785/aggregate-lookup-total-size-of-documents-in-matching-pipeline-exceeds-maximum-d by cc-by-sa and MIT license