MongoDB는 NoSQL이므로 관계형 데이터베이스와 달리 조인이라는 기능이 없다. 하지만 쿼리를 질의하다보면 가끔씩 조인이 필요한 경우가 있다. 그럴 때 aggregate()라는 집계함수를 사용하면 다른 컬렉션을 조인시킬 수 있다.
aggregate는 조인만을 위한 함수는 아니고 보다 복잡한 질의문을 구성할 때 사용하는것인데, 여기서 제공하는 기능 중 $lookup을 사용하면 타 컬렉션과 조인을 할 수 있다고 생각하면 될 것 같다. 먼저 예시를 위해 아래와 같은 도큐먼트가 존재한다고 가정한다.
posts
> db.posts.find()
{ "_id" : ObjectId("5d22de26fc60aab610f73e04"), "post_id" : 1, "user_id" : 1, "body" : "first", "is_block" : false }
{ "_id" : ObjectId("5d22de26fc60aab610f73e05"), "post_id" : 2, "user_id" : 1, "body" : "second", "is_block" : false }
{ "_id" : ObjectId("5d22de26fc60aab610f73e06"), "post_id" : 3, "user_id" : 2, "body" : "third", "is_block" : false }
{ "_id" : ObjectId("5d22de26fc60aab610f73e07"), "post_id" : 4, "user_id" : 3, "body" : "lalala", "is_block" : false }
{ "_id" : ObjectId("5d22de26fc60aab610f73e08"), "post_id" : 5, "user_id" : 4, "body" : "gogo", "is_block" : false }
{ "_id" : ObjectId("5d22de27fc60aab610f73e09"), "post_id" : 6, "user_id" : 5, "body" : "gogo", "is_block" : true }
relationships
> db.relationships.find()
{ "_id" : ObjectId("5d22dd19fc60aab610f73e02"), "user_id" : 1, "target_user_id" : 2 }
{ "_id" : ObjectId("5d22dd1cfc60aab610f73e03"), "user_id" : 1, "target_user_id" : 3 }
여기서 다음과 같은 조건에 맞는 posts를 뽑아내려고 한다.
relationships를 통해 관계되어있는 유저가 작성한 글
만약 user_id=1인 유저가 조회자라고 가정한다면, 다음과 같은 결과가 나와야 한다.
{ "_id" : ObjectId("5d22de26fc60aab610f73e06"), "post_id" : 3, "user_id" : 2, "body" : "third", "is_block" : false }
{ "_id" : ObjectId("5d22de26fc60aab610f73e07"), "post_id" : 4, "user_id" : 3, "body" : "lalala", "is_block" : false }
relationships를 보면 조회하는 유저인 user_id=1에 대해서 2, 3번의 user_id가 관계로 엮여있다. 따라서 2, 3번 유저가 작성한 글만 뽑아져나왔다. 여기서 lookup을 사용하여 아래와 같은 쿼리를 날릴 수 있다.
db.posts.aggregate([
{
$lookup: {
from: 'relationships',
let: {
user_id: "$user_id"
},
pipeline: [{
$match: {
$expr: {
$and: [
{$eq: ["$target_user_id", "$$user_id"]}
]
}
}
}],
as: 'postdata'
},
},
{
$match: {
'postdata': {$ne: []}
}
}
]).pretty()
- from에는 조인시킬 컬렉션 명을 적는다.
- let에 파이프라인에서 사용할 필드명: 변수명을 선언한다.
- pipeline에 실제 조건을 적는다. 나같은 경우, relationships의 target_user_id와 posts의 user_id가 동일한 값만 뽑아내기위한 조건을 줬다. 참고로 말하자면, $$(달러 2개)는 조인 대상 컬렉션의 필드이고 $(달러 1개)는 현재 조회 대상 컬렉션의 필드이다.
- 뽑아낸 값을 as를 통해 담아줬다.
- 마지막으로 $match를 통해 위에서 as를 통해 담아준 값이 []이 아닌 경우 즉, 빈 값이 아닌 경우(존재하는 경우)만 출력하도록 했다.
위 쿼리를 실행하면 아래와 같은 결과를 볼 수 있다.
{
"_id" : ObjectId("5d22de26fc60aab610f73e06"),
"post_id" : 3,
"user_id" : 2,
"body" : "third",
"is_block" : false,
"postdata" : [
{
"_id" : ObjectId("5d22de2dfc60aab610f73e0a"),
"user_id" : 1,
"target_user_id" : 2
}
]
}
{
"_id" : ObjectId("5d22de26fc60aab610f73e07"),
"post_id" : 4,
"user_id" : 3,
"body" : "lalala",
"is_block" : false,
"postdata" : [
{
"_id" : ObjectId("5d22de2efc60aab610f73e0b"),
"user_id" : 1,
"target_user_id" : 3
}
]
}
'Coding' 카테고리의 다른 글
OSX PostgreSQL 정리 (0) | 2019.10.22 |
---|---|
PostgreSQL Partitioning 적용하는 방법 (0) | 2019.08.07 |
Docker Crontab 관련 이슈사항 정리 (0) | 2019.05.22 |
Git rebase 사용하는 방법 (0) | 2019.03.18 |
Flask/Uwsgi/Supervisor 환경변수 문제 해결방법 (0) | 2019.01.04 |