MongoDB에서 참조된 개체를 쿼리하려면 어떻게 해야 합니까?
내 Mongo 데이터베이스에 두 개의 컬렉션이 있고, 그리고.Foo
에는 하나 의 하이에대참에 참조가 되어 있습니다.Bar
s:
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"
기본적으로 주어진 요소의 필드를 키와 값 쌍으로 나누는 연산.:$objectToArray
MongoDB 버전 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-query
Mongoose 스키마를 사용하여 조인할 모델을 결정하고 조인 및 쿼리를 수행할 집계 파이프라인을 만듭니다.
공개:저는 이 사용 사례를 정확하게 다루기 위해 이 라이브러리를 작성했습니다.
언급URL : https://stackoverflow.com/questions/9621928/how-do-i-query-referenced-objects-in-mongodb
'programing' 카테고리의 다른 글
구분 문자열을 목록으로 분할()하는 방법 (0) | 2023.05.02 |
---|---|
데이터 입력 후 문자열을 트리밍하는 가장 좋은 방법입니다.사용자 정의 모델 바인더를 작성해야 합니까? (0) | 2023.05.02 |
PostgreSQL에서 상속된 테이블을 사용해야 하는 경우 (0) | 2023.05.02 |
Postgres SELECT에서 열을 연결하는 방법은 무엇입니까? (0) | 2023.05.02 |
상위 구성 요소의 CSS 파일에서 하위 구성 요소를 스타일화하는 방법은 무엇입니까? (0) | 2023.05.02 |