복붙노트

[MONGODB] $ 조회 후 집계 필터

MONGODB

$ 조회 후 집계 필터

어떻게 $ 조회 후 필터를 추가하거나이 작업을 수행하는 다른 방법이있다 할 수 있습니까?

내 데이터 수집 시험은 다음과 같습니다

{ "_id" : ObjectId("570557d4094a4514fc1291d6"), "id" : 100, "value" : "0", "contain" : [ ] }
{ "_id" : ObjectId("570557d4094a4514fc1291d7"), "id" : 110, "value" : "1", "contain" : [ 100 ] }
{ "_id" : ObjectId("570557d4094a4514fc1291d8"), "id" : 120, "value" : "1", "contain" : [ 100 ] }
{ "_id" : ObjectId("570557d4094a4514fc1291d9"), "id" : 121, "value" : "2", "contain" : [ 100, 120 ] }

나는 ID 100을 선택하고 차일 집계 :

db.test.aggregate([ {
  $match : {
    id: 100
  }
}, {
  $lookup : {
    from : "test",
    localField : "id",
    foreignField : "contain",
    as : "childs"
  }
}]);

난 돌아가 겠어:

{  
  "_id":ObjectId("570557d4094a4514fc1291d6"),
  "id":100,
  "value":"0",
  "contain":[ ],
  "childs":[ {  
      "_id":ObjectId("570557d4094a4514fc1291d7"),
      "id":110,
      "value":"1",
      "contain":[ 100 ]
    },
    {  
      "_id":ObjectId("570557d4094a4514fc1291d8"),
      "id":120,
      "value":"1",
      "contain":[ 100 ]
    },
    {  
      "_id":ObjectId("570557d4094a4514fc1291d9"),
      "id":121,
      "value":"2",
      "contain":[ 100, 120 ]
    }
  ]
}

하지만 난 단지와 일치하는 차일 싶다 "값 : 1"

마지막에 나는이 결과를 기대합니다 :

{  
  "_id":ObjectId("570557d4094a4514fc1291d6"),
  "id":100,
  "value":"0",
  "contain":[ ],
  "childs":[ {  
      "_id":ObjectId("570557d4094a4514fc1291d7"),
      "id":110,
      "value":"1",
      "contain":[ 100 ]
    },
    {  
      "_id":ObjectId("570557d4094a4514fc1291d8"),
      "id":120,
      "value":"1",
      "contain":[ 100 ]
    }
  ]
}

해결법

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

    1.여기에서 문제는 뭔가 다른에 대해 사실과 전혀 조회 $ 필요하지 않습니다. 그러나 누구든지 다음 "$ 조회 한 후 필터링"의 제목에서 순전히 여기 도착 이러한 당신을위한 방법은 다음과 같습니다 :

    여기에서 문제는 뭔가 다른에 대해 사실과 전혀 조회 $ 필요하지 않습니다. 그러나 누구든지 다음 "$ 조회 한 후 필터링"의 제목에서 순전히 여기 도착 이러한 당신을위한 방법은 다음과 같습니다 :

    db.test.aggregate([
        { "$match": { "id": 100 } },
        { "$lookup": {
          "from": "test",
          "let": { "id": "$id" },
          "pipeline": [
            { "$match": {
              "value": "1",
              "$expr": { "$in": [ "$$id", "$contain" ] }
            }}
          ],
          "as": "childs"
        }}
    ])
    
    db.test.aggregate([
        { "$match": { "id": 100 } },
        { "$lookup": {
            "from": "test",
            "localField": "id",
            "foreignField": "contain",
            "as": "childs"
        }},
        { "$unwind": "$childs" },
        { "$match": { "childs.value": "1" } },
        { "$group": {
            "_id": "$_id",
            "id": { "$first": "$id" },
            "value": { "$first": "$value" },
            "contain": { "$first": "$contain" },
            "childs": { "$push": "$childs" }
         }}
    ])
    

    배열에 $ 필터를 사용하여 반대로 것 당신은 언 와인드 $ 이유를 질문하면, 파이프 라인이 일반적으로 필요한 이유에 모든 세부 사항에 대한 최대 문서 크기를 초과 일치에 문서와 훨씬 더 최적의 집계 $ 조회 총 크기를 참조하십시오.

    MongoDB를 3.6 릴리스 및 이후, 다음 더 표현 "하위 파이프 라인은"아무것도 전혀 배열에 반환되기 전에 당신이 외국 모음의 "필터"결과에 원하는 일반적이다.

    위로 대답하는하지만 실제로 .... 문제는 요구를 물었다 전혀 "더 가입"을 설명하지

    이 같은 $ 조회를 사용하면 여기에 원하는 것을 할 수있는 가장 "효율적인"방법이 아니다. 하지만 더이에 이상이 필요합니다.

    기본 개념으로, 단지 결과 배열에 $ 필터를 사용 :

    db.test.aggregate([ 
        { "$match": { "id": 100 } }, 
        { "$lookup": {
            "from": "test",
            "localField": "id",
            "foreignField": "contain",
            "as": "childs"
        }},
        { "$project": {
            "id": 1,
            "value": 1,
            "contain": 1,
            "childs": {
               "$filter": {
                   "input": "$childs",
                   "as": "child",
                   "cond": { "$eq": [ "$$child.value", "1" ] }
               }
            }
        }}
    ]);
    

    또는 $ 편집하다을 대신 사용

    db.test.aggregate([ 
        { "$match": { "id": 100 } }, 
        { "$lookup": {
            "from": "test",
            "localField": "id",
            "foreignField": "contain",
            "as": "childs"
        }},
        { "$redact": {
            "$cond": {
               "if": {
                  "$or": [
                    { "$eq": [ "$value", "0" ] },
                    { "$eq": [ "$value", "1" ] }
                  ]
               },
               "then": "$$DESCEND",
               "else": "$$PRUNE"
            }
        }}
    ]);
    

    모두 같은 결과를 얻을 :

    {  
      "_id":ObjectId("570557d4094a4514fc1291d6"),
      "id":100,
      "value":"0",
      "contain":[ ],
      "childs":[ {  
          "_id":ObjectId("570557d4094a4514fc1291d7"),
          "id":110,
          "value":"1",
          "contain":[ 100 ]
        },
        {  
          "_id":ObjectId("570557d4094a4514fc1291d8"),
          "id":120,
          "value":"1",
          "contain":[ 100 ]
        }
      ]
    }
    

    결론은 특정 데이터를 선택에 $ 쿼리 자체를 할 수없는 조회 "아직"이다. 모든 "필터링"요구는 $ 조회 후 발생하는 그래서

    하지만 실제로는 "자체 가입"이러한 유형의 당신은 더 나은 오프 모두에서 $ 조회를 사용하고 추가로 읽기와 완전히 "해시 병합 '의 오버 헤드를 피할 수 없습니다. 그냥 관련 항목 대신 $ 그룹을 가져 오기 :

    db.test.aggregate([
      { "$match": { 
        "$or": [
          { "id": 100 },
          { "contain.0": 100, "value": "1" }
        ]
      }},
      { "$group": {
        "_id": {
          "$cond": {
            "if": { "$eq": [ "$value", "0" ] },
            "then": "$id",
            "else": { "$arrayElemAt": [ "$contain", 0 ] }
          }
        },
        "value": { "$first": { "$literal": "0"} },
        "childs": {
          "$push": {
            "$cond": {
              "if": { "$ne": [ "$value", "0" ] },
              "then": "$$ROOT",
              "else": null
            }
          }
        }
      }},
      { "$project": {
        "value": 1,
        "childs": {
          "$filter": {
            "input": "$childs",
            "as": "child",
            "cond": { "$ne": [ "$$child", null ] }
          }
        }
      }}
    ])
    

    어느 내가 의도적으로 외부 필드를 제거하기 때문에 조금 밖에 다른 나옵니다. 당신이 정말로 원하는 경우 자신에 추가 :

    {
      "_id" : 100,
      "value" : "0",
      "childs" : [
        {
          "_id" : ObjectId("570557d4094a4514fc1291d7"),
          "id" : 110,
          "value" : "1",
          "contain" : [ 100 ]
        },
        {
          "_id" : ObjectId("570557d4094a4514fc1291d8"),
          "id" : 120,
          "value" : "1",
          "contain" : [ 100 ]
        }
      ]
    }
    

    유일한 진짜 문제는 여기에있다 그래서 현재 문서는 $ 푸시 항목을 처리 할 때 부모가되었을 때 생성 된 배열에서 모든 널 (null) 결과를 "필터링".

    당신이 여기없는 것 같다 당신이 찾고있는 결과가 필요 집계 또는 전부에서 "하위 쿼리를"하지 않습니다. 당신이 가능하게 체결 또는 것을 구조는 그래서 당신은 하나의 질의 요청에 "노드"과의 "아이들"을 모두 얻을 수 있습니다 "설계"되어 다른 곳에서 찾을.

    수단 단지 "쿼리는"커서 결과를 반복 단지 기능 (어떤 내용이 정말 "감소하지"되고 이후 일어나는 모든입니다) 정말 필요한 모든 및 데이터 수집을한다 즉 :

    var result = {};
    
    db.test.find({
      "$or": [
        { "id": 100 },
        { "contain.0": 100, "value": "1" }
      ]
    }).sort({ "contain.0": 1 }).forEach(function(doc) {
      if ( doc.id == 100 ) {
        result = doc;
        result.childs = []
      } else {
        result.childs.push(doc)
      }
    })
    
    printjson(result);
    

    이것은 정확히 같은 일을한다 :

    {
      "_id" : ObjectId("570557d4094a4514fc1291d6"),
      "id" : 100,
      "value" : "0",
      "contain" : [ ],
      "childs" : [
        {
          "_id" : ObjectId("570557d4094a4514fc1291d7"),
          "id" : 110,
          "value" : "1",
          "contain" : [
                  100
          ]
        },
        {
          "_id" : ObjectId("570557d4094a4514fc1291d8"),
          "id" : 120,
          "value" : "1",
          "contain" : [
                  100
          ]
        }
      ]
    }
    

    그리고 당신이 정말로 여기해야 할 모든 문제는 부모와 자녀 모두를 선택할 수있는 "싱글"쿼리는 증거 역할을한다. 반환 된 데이터는 동일합니다, 당신이 중 하나를 서버 또는 클라이언트에서 수행되는 모든 다른 수집 된 형식으로 "마사지"입니다.

    사용이 당신이 당신이 "관계형"데이터베이스에 일을 어떻게했는지 생각에 "잡았다"얻을 수있는 이러한 경우 중 하나이며, 데이터가 저장되는 방식이 "변화"이후 그 실현하지, 더 이상 필요 같은 접근 방식.

    그게 정확히 무엇인지는 쉽게 하나 개의 쿼리 내에서 부모와 자녀를 선택하게 그것의 구조에서 "하위 참조와 모델 트리 구조"문서 예제의 포인트입니다.

  2. from https://stackoverflow.com/questions/36459983/aggregation-filter-after-lookup by cc-by-sa and MIT license