programing

MongoDB에서 참조된 개체를 쿼리하려면 어떻게 해야 합니까?

telebox 2023. 5. 2. 22:35
반응형

MongoDB에서 참조된 개체를 쿼리하려면 어떻게 해야 합니까?

내 Mongo 데이터베이스에 두 개의 컬렉션이 있고, 그리고.Foo에는 하나 의 하이에대참에 참조가 되어 있습니다.Bars:

Foo: { 
  prop1: true,
  prop2: true,
  bars: [
     {
     "$ref": "Bar",
     "$id": ObjectId("blahblahblah")
     }
  ]
}

Bar: {
   testprop: true
}

내가 원하는 것은 모든 것을 찾는 것입니다.Foo의 나하이포함는하가 있는 s.Bar테스트 프롭이 true로 설정되어 있습니다.명령어를안 요: 명령을사용보반않결습지다니되이환가과만지았해.

db.Foo.find({ "bars.testprop" : { "$in": [ true ] } })

아이디어 있어요?

이제 Mongo 3.2에서 다음을 사용하여 수행할 수 있습니다.

$lookup를 사용합니다.

from조인을 수행할 동일한 데이터베이스의 컬렉션을 지정합니다.원본 컬렉션을 샤드할 수 없습니다.

localField문서 입력에서 $lookup 단계까지의 필드를 지정합니다.$lookup은 from 컬렉션의 문서에서 localField와 foreignField를 동등하게 일치시킵니다.

foreignField원본 컬렉션의 문서에서 필드를 지정합니다.

as입력 문서에 추가할 새 배열 필드의 이름을 지정합니다.새 배열 필드에는 원본 컬렉션의 일치하는 문서가 들어 있습니다.

db.Foo.aggregate(
  {$unwind: "$bars"},
  {$lookup: {
    from:"bar",
    localField: "bars",
    foreignField: "_id",
    as: "bar"

   }},
   {$match: {
    "bar.testprop": true
   }}
)

그럴수는 없어요.http://www.mongodb.org/display/DOCS/Database+References 을 참조하십시오.

당신은 그것을 고객에게 해야 합니다.

3.4.4, 3.를 3.5.5)와 와 함께 사용하는 과 유사한 .@Referenece두 개의 실체에.우리는 이 솔루션에 만족하지 않으며 이러한 선언을 삭제하고 대신 참조 검색을 수동으로 수행하는 것을 고려하고 있습니다.

즉, 회사 컬렉션과 사용자 컬렉션이 있습니다.에는 Morphia 사의다포있함습다니어되이음이 포함되어 .@Refrence 에는 다음 항목이 되어 있습니다.

/* 1 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5dee"),
    "name" : "Test",
    "gln" : "1234567890123",
    "uuid" : "f1f86961-e8d5-40bb-9d3f-fdbcf549066e",
    "creationDate" : ISODate("2017-09-01T09:14:41.551Z"),
    "lastChange" : ISODate("2017-09-01T09:14:41.551Z"),
    "version" : NumberLong(1),
    "disabled" : false
}

/* 2 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5def"),
    "name" : "Sample",
    "gln" : "3210987654321",
    "uuid" : "fee69ee4-b29c-483b-b40d-e702b50b0451",
    "creationDate" : ISODate("2017-09-01T09:14:41.562Z"),
    "lastChange" : ISODate("2017-09-01T09:14:41.562Z"),
    "version" : NumberLong(1),
    "disabled" : false
}

사용자 컬렉션에는 다음 항목이 포함되어 있습니다.

/* 1 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df0"),
    "userId" : "admin",
    "userKeyEncrypted" : {
        "salt" : "78e0528db239fd86",
        "encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
    },
    "passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
    "roles" : [ 
        "ADMIN"
    ],
    "company" : {
        "$ref" : "company",
        "$id" : ObjectId("59a92501df01110fbb6a5dee")
    },
    "uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
    "creationDate" : ISODate("2017-09-01T09:14:41.673Z"),
    "lastChange" : ISODate("2017-09-01T09:14:41.765Z"),
    "version" : NumberLong(1),
    "disabled" : false
}

/* 2 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df1"),
    "userId" : "sample",
    "userKeyEncrypted" : {
        "salt" : "e3ac48695dea5f51",
        "encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
    },
    "passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
    "roles" : [ 
        "USER"
    ],
    "company" : {
        "$ref" : "company",
        "$id" : ObjectId("59a92501df01110fbb6a5def")
    },
    "uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
    "creationDate" : ISODate("2017-09-01T09:14:41.873Z"),
    "lastChange" : ISODate("2017-09-01T09:14:41.878Z"),
    "version" : NumberLong(1),
    "disabled" : false
}

/* 3 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df2"),
    "userId" : "user",
    "userKeyEncrypted" : {
        "salt" : "ab9df671340a7d8b",
        "encryptedAttribute" : "7d8ad4ca6ad88686d810c70498407032f1df830596f72d931880483874d9cce3"
    },
    "passwordHash" : "$2a$10$0FLFw3ixW79JIBrD82Ly6ebOwnEDliS.e7GmrNkFp2nkWDA9OE/RC",
    "uuid" : "d02aef94-fc3c-4539-a22e-e43b8cd78aaf",
    "creationDate" : ISODate("2017-09-01T09:14:41.991Z"),
    "lastChange" : ISODate("2017-09-01T09:14:41.995Z"),
    "version" : NumberLong(1),
    "disabled" : false
}

특수 회사 사용자 뷰를 만들기 위해 사용자의 회사 참조를 취소하고 선택한 필드만 포함하려고 했습니다.버그 보고서 내의 코멘트를 바탕으로 우리는 MongoDB가 제공하는 것을 배웠습니다.$objectToArray: "$$ROOT.element"기본적으로 주어진 요소의 필드를 키와 값 쌍으로 나누는 연산.:$objectToArrayMongoDB 버전 3.4.4에 작업이 추가되었습니다!

하여 집계한 것입니다.$objectToArray작동은 다음과 같습니다.

dp.user.aggregate([{ 
    $project: { 
        "userId": 1, 
        "userKeyEncrypted": 1, 
        "uuid":1, 
        "roles": 1, 
        "passwordHash": 1, 
        "disabled": 1, 
        company: { $objectToArray: "$$ROOT.company" }
    } 
}])

위의 집계 결과는 다음과 같습니다.

/* 1 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df0"),
    "userId" : "admin",
    "userKeyEncrypted" : {
        "salt" : "78e0528db239fd86",
        "encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
    },
    "passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
    "roles" : [ 
        "ADMIN"
    ],
    "uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
    "disabled" : false,
    "company" : [ 
        {
            "k" : "$ref",
            "v" : "company"
        }, 
        {
            "k" : "$id",
            "v" : ObjectId("59a92501df01110fbb6a5dee")
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df1"),
    "userId" : "sample",
    "userKeyEncrypted" : {
        "salt" : "e3ac48695dea5f51",
        "encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
    },
    "passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
    "roles" : [ 
        "USER"
    ],
    "uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
    "disabled" : false,
    "company" : [ 
        {
            "k" : "$ref",
            "v" : "company"
        }, 
        {
            "k" : "$id",
            "v" : ObjectId("59a92501df01110fbb6a5def")
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df2"),
    "userId" : "user",
    "userKeyEncrypted" : {
        "salt" : "ab9df671340a7d8b",
        "encryptedAttribute" : "7d8ad4ca6ad88686d810c70498407032f1df830596f72d931880483874d9cce3"
    },
    "passwordHash" : "$2a$10$0FLFw3ixW79JIBrD82Ly6ebOwnEDliS.e7GmrNkFp2nkWDA9OE/RC",
    "uuid" : "d02aef94-fc3c-4539-a22e-e43b8cd78aaf",
    "disabled" : false,
    "company" : null
}

이제는 불필요한 것(즉, 회사가 할당되지 않은 사용자 및 올바른 어레이 항목 선택)을 필터링하여 사용자에게 제공하는 것입니다.$lookup@sidgate 운영은 이미 참조되지 않은 회사의 값을 설명하고 사용자 응답에 복사했습니다.

즉, 아래와 같은 집합체는 조인을 수행하고 회사가 할당된 사용자에게 회사의 데이터를 추가합니다.as조회에 정의된 값:

db.user.aggregate([
    { $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, company: { $objectToArray: "$$ROOT.company" }} }, 
    { $unwind: "$company" }, 
    { $match: { "company.k": "$id"}  }, 
    { $lookup: { from: "company", localField: "company.v", foreignField: "_id", as: "company_data" } }
])

위의 집계 결과는 다음과 같습니다.

/* 1 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df0"),
    "userId" : "admin",
    "userKeyEncrypted" : {
        "salt" : "78e0528db239fd86",
        "encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
    },
    "passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
    "roles" : [ 
        "ADMIN"
    ],
    "uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
    "disabled" : false,
    "company" : {
        "k" : "$id",
        "v" : ObjectId("59a92501df01110fbb6a5dee")
    },
    "company_data" : [ 
        {
            "_id" : ObjectId("59a92501df01110fbb6a5dee"),
            "name" : "Test",
            "gln" : "1234567890123",
            "uuid" : "f1f86961-e8d5-40bb-9d3f-fdbcf549066e",
            "creationDate" : ISODate("2017-09-01T09:14:41.551Z"),
            "lastChange" : ISODate("2017-09-01T09:14:41.551Z"),
            "version" : NumberLong(1),
            "disabled" : false
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df1"),
    "userId" : "sample",
    "userKeyEncrypted" : {
        "salt" : "e3ac48695dea5f51",
        "encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
    },
    "passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
    "roles" : [ 
        "USER"
    ],
    "uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
    "disabled" : false,
    "company" : {
        "k" : "$id",
        "v" : ObjectId("59a92501df01110fbb6a5def")
    },
    "company_data" : [ 
        {
            "_id" : ObjectId("59a92501df01110fbb6a5def"),
            "name" : "Sample",
            "gln" : "3210987654321",
            "uuid" : "fee69ee4-b29c-483b-b40d-e702b50b0451",
            "creationDate" : ISODate("2017-09-01T09:14:41.562Z"),
            "lastChange" : ISODate("2017-09-01T09:14:41.562Z"),
            "version" : NumberLong(1),
            "disabled" : false
        }
    ]
}

바라건대, 우리는 회사 참조를 포함한 두 명의 사용자만 가지고 있으며, 이제 두 명의 사용자도 응답에 대한 전체 회사 데이터를 가지고 있습니다.이제 추가 필터링을 적용하여 키/값 도우미를 제거하고 원하지 않는 데이터를 숨길 수 있습니다.

우리가 생각해 낸 마지막 질문은 다음과 같습니다.

db.user.aggregate([
    { $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, company: { $objectToArray: "$$ROOT.company" }} }, 
    { $unwind: "$company" }, 
    { $match: { "company.k": "$id"}  }, 
    { $lookup: { from: "company", localField: "company.v", foreignField: "_id", as: "company_data" } },
    { $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1,  "companyUuid": { $arrayElemAt: [ "$company_data.uuid", 0 ] } } }
])

마침내 우리가 원하는 표현을 반환합니다.

/* 1 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df0"),
    "userId" : "admin",
    "userKeyEncrypted" : {
        "salt" : "78e0528db239fd86",
        "encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
    },
    "passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
    "roles" : [ 
        "ADMIN"
    ],
    "uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
    "disabled" : false,
    "companyUuid" : "f1f86961-e8d5-40bb-9d3f-fdbcf549066e"
}

/* 2 */
{
    "_id" : ObjectId("59a92501df01110fbb6a5df1"),
    "userId" : "sample",
    "userKeyEncrypted" : {
        "salt" : "e3ac48695dea5f51",
        "encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
    },
    "passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
    "roles" : [ 
        "USER"
    ],
    "uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
    "disabled" : false,
    "companyUuid" : "fee69ee4-b29c-483b-b40d-e702b50b0451"
}

이 접근 방식에 대한 마지막 참고 사항:이 집계는 그리 빠르지는 않지만, 슬프게도, 적어도 일을 완수합니다.원래 요청한 것처럼 일련의 참조 자료를 사용하여 테스트하지는 않았지만, 추가적인 감김이 필요할 수도 있습니다.


업데이트: 위에서 언급한 버그 보고서의 설명과 더 일치하는 데이터를 집계하는 추가 방법은 아래에서 확인할 수 있습니다.

db.user.aggregate([
    { $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, companyRefs: { $let: { vars: { refParts: { $objectToArray: "$$ROOT.company" }}, in: "$$refParts.v" } } } },
    { $match: { "companyRefs": { $exists: true } } },
    { $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, "companyRef": { $arrayElemAt: [ "$companyRefs", 1 ] } } },
    { $lookup: { from: "company", localField: "companyRef", foreignField: "_id", as: "company_data" } },
    { $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1,  "companyUuid": { $arrayElemAt: [ "$company_data.uuid", 0 ] } } }
])

, 여, 서기.$let: { vars: ..., in: ... }작업은 참조의 키와 값을 자체 개체로 복사하므로 나중에 해당 작업을 통해 참조를 조회할 수 있습니다.

이러한 집계 중 어느 것이 더 나은 성능을 발휘하는지는 아직 설명되지 않았습니다.

은 그에게 할 수 . 당신은 질문할 수 있습니다.Bar 모델_id에 관한 모든 서류 중에서.testprop: true 찾기를 합니다.$in 및채기우에 합니다.bars에서.Foo _id첫 번째 질문에서 얻은 것입니다.:P

아마도 그것은 "고객 속에서"로 간주될 것입니다: 그냥 생각일 뿐입니다.

이전에는 불가능했지만, Mongo v3.4의 개선 사항은 매우 가까이 접근할 수 있습니다.

로 할 수 있습니다. 코드는 다음과 같습니다.

const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.Foo,
    {
        find: { "bars.testprop": { $in: [true] } },
        populate: ["bars"]
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

어떻게 작동합니까?

mongo-join-queryMongoose 스키마를 사용하여 조인할 모델을 결정하고 조인 및 쿼리를 수행할 집계 파이프라인을 만듭니다.

공개:저는 이 사용 사례를 정확하게 다루기 위해 이 라이브러리를 작성했습니다.

언급URL : https://stackoverflow.com/questions/9621928/how-do-i-query-referenced-objects-in-mongodb

반응형