programing

DBef로 $lookup하는 Mongo 방법

lastcode 2023. 7. 16. 13:33
반응형

DBef로 $lookup하는 Mongo 방법

문제가 생겼어요.컬렉션 A가 다음과 같다고 가정합니다.

{ 
    "_id" : ObjectId("582abcd85d2dfa67f44127e1"), 
    "bid" : [
        DBRef("B", ObjectId("582abcd85d2dfa67f44127e0")),
        DBRef("B", ObjectId("582abcd85d2dfa67f44127e1"))
    ]
}


및 컬렉션 B:

{ 
    "_id" : ObjectId("582abcd85d2dfa67f44127e0"),  
    "status" : NumberInt(1), 
    "seq" : NumberInt(0)
},
{ 
    "_id" : ObjectId("582abcd85d2dfa67f44127e1"), 
    "status" : NumberInt(1), 
    "seq" : NumberInt(0)
} 


나는 '입찰'을 어떻게 조회하는지 모릅니다.나는 노력했다.

db.A.aggregate(
    [
        {$unwind: {path: "$bid"}},
        {$lookup: {from: "B", localField: "bid", foreignField: "_id", as: "bs"}},
    ]
) 


그리고.

db.A.aggregate(
    [
        {$unwind: {path: "$bid"}},
        {$lookup: {from: "B", localField: "bid.$id", foreignField: "_id", as: "bs"}},
    ]
)


하지만 효과가 없습니다.도와줄 사람?감사해요.

사실 다른 답은 틀렸습니다.애그리게이터 내에서 DBref 필드를 조회할 수 있으며, 맵 축소가 필요하지 않습니다.

해결책

db.A.aggregate([
{
    $project: { 
        B_fk: {
          $map: { 
             input: { 
                  $map: {
                      input:"$bid",
                      in: {
                           $arrayElemAt: [{$objectToArray: "$$this"}, 1]
                      },
                  }
             },
             in: "$$this.v"}},
        }
}, 
{
    $lookup: {
        from:"B", 
        localField:"B_fk",
        foreignField:"_id", 
        as:"B"
    }
}
])

결과

{
    "_id" : ObjectId("59bb79df1e9c00162566f581"),
    "B_fk" : null,
    "B" : [ ]
},
{
    "_id" : ObjectId("582abcd85d2dfa67f44127e1"),
    "B_fk" : [
        ObjectId("582abcd85d2dfa67f44127e0"),
        ObjectId("582abcd85d2dfa67f44127e1")
    ],
    "B" : [
        {
            "_id" : ObjectId("582abcd85d2dfa67f44127e0"),
            "status" : NumberInt("1"),
            "seq" : NumberInt("0")
        }
    ]
}

짧은 설명

$map을 사용하여 DBref를 반복하고 각 DBref를 배열로 분할한 다음 $id 필드만 유지한 다음 $$this.v를 사용하여 k:v 형식을 제거하고 ObjectId만 유지하고 나머지는 모두 제거합니다.이제 ObjectId를 조회할 수 있습니다.

단계별 설명

애그리게이터 내에서 DBRef BSON 유형은 두 개 또는 세 개의 필드(ref, id 및 db)로 객체처럼 처리할 수 있습니다.

수행하는 경우:

db.A.aggregate([
    {
        $project: { 
            First_DBref_as_array: {$objectToArray:{$arrayElemAt:["$bid",0]}},
            Second_DBref_as_array: {$objectToArray:{$arrayElemAt:["$bid",1]}},
            }

    },

])

결과는 다음과 같습니다.

{
"_id" : ObjectId("582abcd85d2dfa67f44127e1"),
"First_DBref_as_array : [
    {
        "k" : "$ref",
        "v" : "B"
    },
    {
        "k" : "$id",
        "v" : ObjectId("582abcd85d2dfa67f44127e0")
    }
],
"Second_DBref_as_array" : [
    {
        "k" : "$ref",
        "v" : "B"
    },
    {
        "k" : "$id",
        "v" : ObjectId("582abcd85d2dfa67f44127e0")
    }
]
}

dbref를 배열로 변환한 후에는 다음과 같이 인덱스 1의 값만 쿼리하여 쓸모없는 필드를 제거할 수 있습니다.

db.A.aggregate([
    {
        $project: { 
            First_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]},
            Second_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]},
            }

    },

])

결과:

{
    "_id" : ObjectId("582abcd85d2dfa67f44127e1"),
    "First_DBref_as_array" : {
        "k" : "$id",
        "v" : ObjectId("582abcd85d2dfa67f44127e0")
    },
    "Second_DBref_as_array" : {
        "k" : "$id",
        "v" : ObjectId("582abcd85d2dfa67f44127e0")
    }
}

그런 다음 "$myvalue"를 가리키면 마침내 원하는 값에 도달할 수 있습니다.v", 이와 같이

db.A.aggregate([
    {
        $project: { 
            first_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]},
            second_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]},
            }

    },
    {
        $project: {
            first_DBref_as_ObjectId: "$first_DBref_as_array.v",
            second_DBref_as_ObjectId: "$second_DBref_as_array.v"
        }
    }

])

결과:

{
    "_id" : ObjectId("582abcd85d2dfa67f44127e1"),
    "first_DBref_as_ObjectId" : ObjectId("582abcd85d2dfa67f44127e0"),
    "second_DBref_as_ObjectId" : ObjectId("582abcd85d2dfa67f44127e0")
}

일반적인 파이프라인에서는 이러한 중복 단계가 모두 필요하지 않으며, 중첩된 $map을 사용하면 한 번에 동일한 결과를 얻을 수 있습니다.

db.A.aggregate([
    {
        $project: { 
            B_fk: { $map : {input: { $map: {    input:"$bid",
                                    in: { $arrayElemAt: [{$objectToArray: "$$this"}, 1 ]}, } },
                            in: "$$this.v"}},

            }
    }, 

])

결과:

{
    "_id" : ObjectId("582abcd85d2dfa67f44127e1"),
    "B_fk" : [
        ObjectId("582abcd85d2dfa67f44127e0"),
        ObjectId("582abcd85d2dfa67f44127e1")
    ]
}

자유롭게 묻지는 않더라도 충분히 설명이 명확했으면 좋겠습니다.

mongoDB 3.4 이후로는 이것이 불가능합니다.$match 단계를 제외하고 집계 파이프라인에서 DBRef를 사용할 수 없습니다.

DBef를 없애고 수동 참조로 전환하는 것이 좋습니다.하지만 DBEf를 유지해야 하는 경우 다음과 같은 (못된) 해결책이 있습니다.

먼저 "C"라는 이름의 새 컬렉션을 생성합니다. 여기서 mapReduce:

db.A.mapReduce(
    function() {
        var key = this._id; 
        var value = [];  
        for ( var index = 0; index < this.bid.length; index++){
           value.push(this.bid[index].$id); 
        }
        emit(key, value); 
    },
    function(key,values) {
        return  values;
    },
    {
        "query": {},
        "out": "C" 
    }
)

그런 다음 새 "C" 컬렉션에 대해 집계 쿼리를 실행합니다.

db.C.aggregate([
   {
      $unwind:"$value"
   },
   {
      $lookup:{
         from:"B",
         localField:"value",
         foreignField:"_id",
         as:"bs"
      }
   }
]);

출력:

    {
       "_id":ObjectId("582abcd85d2dfa67f44127e1"),
       "value":ObjectId("582abcd85d2dfa67f44127e0"),
       "bs":[
          {
             "_id":ObjectId("582abcd85d2dfa67f44127e0"),
             "status":1,
             "seq":0
          }
       ]
    }{
       "_id":ObjectId("582abcd85d2dfa67f44127e1"),
       "value":ObjectId("582abcd85d2dfa67f44127e1"),
       "bs":[
          {
             "_id":ObjectId("582abcd85d2dfa67f44127e1"),
             "status":1,
             "seq":0
          }
       ]
    }

2021년에 누군가가 이곳에 올 경우를 대비해서:

MongoDB 4.3.3부터는 OP의 두 번째 쿼리가 작동합니다.

db.A.aggregate(
    [
        {$unwind: {path: "$bid"}},
        {$lookup: {from: "B", localField: "bid.$id", foreignField: "_id", as: "bs"}},
    ]
)

결과는 다음과 같습니다.

{
   "_id":ObjectId("582abcd85d2dfa67f44127e1"),
   "bid":DBRef("B", "ObjectId("582abcd85d2dfa67f44127e0")),
   "bs":[
      {
         "_id":ObjectId("582abcd85d2dfa67f44127e0")",
         "status":1,
         "seq":0
      }
   ]
}{
   "_id":ObjectId("582abcd85d2dfa67f44127e1"),
   "bid":DBRef("B", "ObjectId("582abcd85d2dfa67f44127e1")),
   "bs":[
      {
         "_id":ObjectId("582abcd85d2dfa67f44127e1"),
         "status":1,
         "seq":0
      }
   ]
}

자세한 내용은 SERVER-14466을 참조하십시오.

언급URL : https://stackoverflow.com/questions/40622714/mongo-how-to-lookup-with-dbref

반응형