prosource

$lookup 연산자를 사용한 다중 조인 조건

probook 2023. 6. 2. 20:36
반응형

$lookup 연산자를 사용한 다중 조인 조건

다음 두 가지 컬렉션이 있습니다.

// collection1:
{
  user1: 1,
  user2: 2,
  percent: 0.56
}

// collection2:
{
  user1: 1,
  user2: 2,
  percent: 0.3
}

는 이 두 .user1그리고.user2.

다음과 같은 결과를 얻으려면 파이프라인을 작성하는 방법:

{
  user1: 1,
  user2: 2,
  percent1: 0.56,
  percent2: 0.3
}

버전 3.6 이상에서는 집계 파이프라인 운영자와 여러 조인 조건을 수행할 수 있습니다.

다을사여필값변할합당니다야해를 해야 합니다.let필드에서 수 있습니다.pipeline집합에서 실행할 파이프라인을 지정하는 필드 단계.

로 고에서는 다음을 수행합니다.$match평가 쿼리 연산자를 사용하여 필드 값을 비교합니다.

파이프라인의 마지막 단계는 통합 파이프라인 단계입니다. 여기서 우리는 간단히 통합합니다.$lookup의일로 결과인의 .$$ROOT오퍼레이터를 사용하여 문서화합니다.

db.collection2.aggregate([
       {
          $lookup: {
             from: "collection1",
             let: {
                firstUser: "$user1",
                secondUser: "$user2"
             },
             pipeline: [
                {
                   $match: {
                      $expr: {
                         $and: [
                            {
                               $eq: [
                                  "$user1",
                                  "$$firstUser"
                               ]
                            },
                            {
                               $eq: [
                                  "$user2",
                                  "$$secondUser"
                               ]
                            }
                         ]
                      }
                   }
                }
             ],
             as: "result"
          }
       },
       {
          $replaceRoot: {
             newRoot: {
                $mergeObjects:[
                   {
                      $arrayElemAt: [
                         "$result",
                         0
                      ]
                   },
                   {
                      percent1: "$$ROOT.percent1"
                   }
                ]
             }
          }
       }
    ]
)

이 파이프라인은 다음과 같은 결과를 산출합니다.

{
    "_id" : ObjectId("59e1ad7d36f42d8960c06022"),
    "user1" : 1,
    "user2" : 2,
    "percent" : 0.3,
    "percent1" : 0.56
}

버전 3.6+가 아닌 경우, 먼저 필드 중 하나를 사용하여 "user1"로 입력하고 여기서 집합 파이프라인 연산자를 사용하여 일치하는 문서의 배열을 풀 수 있습니다.파이프라인의 다음 단계는 및 시스템 변수를 사용하여 "가입된" 집합과 입력 문서의 "user2" 값이 동일하지 않은 문서를 필터링하는 단계입니다.그런 다음 단계에서 문서의 모양을 변경할 수 있습니다.

db.collection1.aggregate([
    { "$lookup": { 
        "from": "collection2", 
        "localField": "user1", 
        "foreignField": "user1", 
        "as": "collection2_doc"
    }}, 
    { "$unwind": "$collection2_doc" },
    { "$redact": { 
        "$cond": [
            { "$eq": [ "$user2", "$collection2_doc.user2" ] }, 
            "$$KEEP", 
            "$$PRUNE"
        ]
    }}, 
    { "$project": { 
        "user1": 1, 
        "user2": 1, 
        "percent1": "$percent", 
        "percent2": "$collection2_doc.percent"
    }}
])

이는 다음을 생성합니다.

{
    "_id" : ObjectId("572daa87cc52a841bb292beb"),
    "user1" : 1,
    "user2" : 2,
    "percent1" : 0.56,
    "percent2" : 0.3
}

컬렉션의 문서 구조가 동일하고 이 작업을 자주 수행하는 경우 두 컬렉션을 하나로 병합하거나 해당 컬렉션의 문서를 새 컬렉션에 삽입해야 합니다.

db.collection3.insertMany(
    db.collection1.find({}, {"_id": 0})
    .toArray()
    .concat(db.collection2.find({}, {"_id": 0}).toArray())
)

그런 다음 "user1" 및 "user2"별로 문서를 작성합니다.

db.collection3.aggregate([
    { "$group": {
        "_id": { "user1": "$user1", "user2": "$user2" }, 
        "percent": { "$push": "$percent" }
    }}
])

다음과 같은 결과:

{ "_id" : { "user1" : 1, "user2" : 2 }, "percent" : [ 0.56, 0.3 ] }

하는 중Mongo 4.4우리는 고전과 결합된 새로운 집계 단계를 통해 이러한 유형의 "데이터 세트"를 달성할 수 있습니다.$group선택 사항:

// > db.collection1.find()
//   { "user1" : 1, "user2" : 2, "percent" : 0.56 }
//   { "user1" : 4, "user2" : 3, "percent" : 0.14 }
// > db.collection2.find()
//   { "user1" : 1, "user2" : 2, "percent" : 0.3  }
//   { "user1" : 2, "user2" : 3, "percent" : 0.25 }
db.collection1.aggregate([
  { $set: { percent1: "$percent" } },
  { $unionWith: {
    coll: "collection2",
    pipeline: [{ $set: { percent2: "$percent" } }]
  }},
  { $group: {
    _id: { user1: "$user1", user2: "$user2" },
    percents: { $mergeObjects: { percent1: "$percent1", percent2: "$percent2" } }
  }}
])
// { _id: { user1: 1, user2: 2 }, percents: { percent1: 0.56, percent2: 0.3 } }
// { _id: { user1: 2, user2: 3 }, percents: { percent2: 0.25 } }
// { _id: { user1: 4, user2: 3 }, percents: { percent1: 0.14 } }

다음 항목:

  • 새 단계를 통해 두 컬렉션을 파이프라인으로 통합하는 것으로 시작합니다.

    • 이름을 먼저 변경합니다.percentcollection1percent1(() $set스테이지)
    • $unionWith단는, 우리지니다를 합니다.pipeline에서.collection2이도바위해기의 이름을 바꾸기 도.percent에는 이에는에번▁this▁time.percent2.
    • 이렇게 하면 백분율 필드의 원점을 구별할 수 있습니다.
  • 다음으로 계속됩니다.$group단계:

    • 다음을 기준으로 레코드를 그룹화합니다.user1그리고.user2
    • 작업을 통해 백분율을 누적합니다.사용.$first: "$percent1"그리고.$first: "$percent2"잠재적으로 시간이 걸릴 수 있기 때문에 작동하지 않을 것입니다.null먼저(다른 컬렉션의 요소의 경우).반면에.$mergeObjects버림받은 물건null가치.

다른 출력 형식이 필요한 경우 다운스트림을 추가할 수 있습니다.$project단계.

데이터를 모델링하려고 하는데 mongodb가 여러 필드에서 조인을 수행할 수 있는지 확인하기 위해 여기에 왔다면 계속 읽어보십시오.

MongoDB는 조인을 수행할 수 있지만 애플리케이션 액세스 패턴에 따라 데이터를 모델링할 수도 있습니다.데이터가 질문에 제시된 것처럼 단순한 경우 다음과 같은 단일 컬렉션을 유지할 수 있습니다.

{
    user1: 1,
    user2: 2,
    percent1: 0.56,
    percent2: 0.3
}

이제 참여하여 수행했을 이 컬렉션에 대한 모든 작업을 수행할 수 있습니다.우리는 왜 조인을 피하려고 합니까?문서는 필요할 때 확장할 수 없도록 샤드 컬렉션(doc)에서 지원되지 않기 때문입니다.(이제 조인은 샤드 컬렉션에서 지원됨) 데이터 정규화(별도의 테이블/수집 포함)는 SQL에서 매우 잘 작동하지만 Mongo의 경우 조인을 피하는 것이 대부분의 경우 결과 없이 이점을 제공할 수 있습니다.MongoDB에서 정규화는 다른 선택이 없는 경우에만 사용하십시오.문서에서:

일반적으로 정규화된 데이터 모델을 사용합니다.

  • 임베딩이 데이터의 중복을 초래하지만 중복의 의미를 능가할 만큼 충분한 읽기 성능 이점을 제공하지 못할 경우.
  • 더 복잡한 다대다 관계를 나타냅니다.
  • 대형 계층 데이터 세트를 모형화합니다.

임베딩에 대한 자세한 내용과 정규화 대신 임베딩을 선택하는 이유를 보려면 여기를 확인하십시오.

$match 및 $project 파이프라인을 사용하여 여러 필드 일치를 수행할 수 있습니다.(자세한 답변은 여기를 참조하십시오 - mongoDB 여러 필드에 가입)

db.collection1.aggregate([
                    {"$lookup": {
                    "from": "collection2",
                    "localField": "user1",
                    "foreignField": "user1",
                    "as": "c2"
                    }},
                    {"$unwind": "$c2"},

                    {"$project": {
                    "user2Eq": {"$eq": ["$user2", "$c2.user2"]},
                    "user1": 1, "user2": 1, 
                    "percent1": "$percent", "percent2": "$c2.percent"
                    }},

                    {"$match": {
                    {"user2Eq": {"$eq": True}}
                    }},

                    {"$project": {
                    "user2Eq": 0
                    }}

                    ])

언급URL : https://stackoverflow.com/questions/37086387/multiple-join-conditions-using-the-lookup-operator

반응형