$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 } }
다음 항목:
새 단계를 통해 두 컬렉션을 파이프라인으로 통합하는 것으로 시작합니다.
- 이름을 먼저 변경합니다.
percent
collection1
percent1
(()$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
'prosource' 카테고리의 다른 글
텍스트 뷰 텍스트를 경계 내에 맞게 자동 축척 (0) | 2023.06.02 |
---|---|
해시/AML에서 모든 빈 요소를 제거하시겠습니까? (0) | 2023.06.02 |
Ruby Array find_first 객체? (0) | 2023.06.02 |
Excel: 셀에서 여러 용어 검색 (0) | 2023.06.02 |
Visual Basic에서 문자열을 정수로 변환하려면 어떻게 해야 합니까? (0) | 2023.06.02 |