👨🏫 고급(?) stage
$bucket
https://docs.mongodb.com/manual/reference/operator/aggregation/bucket/
흔히 말하는 '버케팅'을 합니다. 버케팅하려는 값이 정수면 $group을 사용하고, 실수면 $bucket이 좋습니다.
왜냐하면 $bucket은 값을 제각각 나누는 것이 아니라 범위로 나누거든요.
{
$bucket: {
groupBy: <expression>, // 버케팅할 기준
boundaries: [ <lowerbound1>, <lowerbound2>, ... ], // 버케팅 기준값의 구간
default: <literal>, // optional. 구간 외의 도큐먼트를 처리할 필드명
output: {
<output1>: { <$accumulator expression> }, // optional. 버케팅한 후 출력 결과를 표시할 방법
...
<outputN>: { <$accumulator expression> }
}
}
}
rating 기준으로 묶고, 구간은 [2, 3), [3, 5) 가 됩니다.
* 개구간, 폐구간, 반개구간은 아시죠? (a,b)={x∈R∣a<x<b}, [a,b]={x∈R∣a≤x≤b}
이 구간 내에 속하지 않는 도큐먼트는 _id가 Others가 되고요.
최종적으로 출력할 모습은 {"count": ..., "user_ids": [...]} 모양이 되겠네요.
db.rating.aggregate([
{$bucket: {
groupBy: "$rating",
boundaries: [2, 3, 5],
default: "Others",
output: {
count: {$sum: 1},
user_ids: {$push: "$user_id"}
}
}}
])
출력된 결과물은 다음과 같습니다.
{"_id" : 2.0, "count" : 1.0, "user_ids" : [3.0]}
{"_id" : 3.0, "count" : 4.0, "user_ids" : [4.0, 1.0, 7.0, 8.0]}
{"_id" : "Others", "count" : 5.0, "user_ids" : [2.0, 6.0, 9.0, 10.0, 5.0]}
$bucketAuto
https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/
$bucket이 특정 구간을 수작업으로 지정했다면, $bucketAuto는 범위를 자동으로 설정해준다.
{
$bucketAuto: {
groupBy: <expression>, // 버케팅할 기준
buckets: <number>, // 몇 개의 그룹으로 나눌 것인가?
output: {
<output1>: { <$accumulator expression> }, // optional
...
}
granularity: <string> // 어떤 수열로 버케팅 기준을 분류할 것인가
}
}
granularity에 올 수 있는 값은 다음과 같다.
R로 시작하는 것은 레나드 수열
E로 시작하는 것은 E수열
1-2-5는 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50...로 이어지는 수열
POWERSOF2는 공비(r)가 2인 등비수열
|
|
$addFields
https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/
새로운 필드를 생성할 수 있다. 만약, 생성하고자 하는 필드가 존재하면 덮어쓰고, 점 연산자를 통해 임베디드 도큐먼트에도 필드를 추가할 수 있다.
{ $addFields: { <newField>: <expression>, ... } }
// nice라는 필드를 새로 만들고 boat라는 문자열을 할당합니다.
db.rating.aggregate([
{$addFields: {nice: "boat"}},
{$limit: 5}
])
$facet
https://docs.mongodb.com/manual/reference/operator/aggregation/facet/
facet을 번역하면 양상(그러니까 그냥 일이나 상황이 보여지는 방식)이다.
도큐먼트를 집계해서 정해진 필드에 연산 결과를 배열 형식으로 값을 출력한다.
쉽게 말해, 여러가지 stage를 거친 값들을 출력한다는 것이다.
{ $facet:
{
<outputField1>: [ <stage1>, <stage2>, ... ],
<outputField2>: [ <stage1>, <stage2>, ... ],
...
}
}
예시를 보면, byRating이란 필드 명으로 출력할 stage들이 보이고, byId란 필드 명으로 출력할 stage들이 보인다.
$facet은 여러 정보를 동시에 보고 싶을 때 사용하면 유용하다.
db.rating.aggregate([
{$facet: {
byRating: [
{$group: {_id: "$rating", count: {$sum: 1}}}
],
byId: [
{$bucketAuto: {groupBy: "$_id", buckets: 5}}
]
}},
])
{
"byRating" : [
{
"_id" : 5.0,
"count" : 4.0
},
{
"_id" : 1.0,
"count" : 1.0
},
... 중략
],
"byId" : [
{
"_id" : {
"min" : 1.0,
"max" : 3.0
},
"count" : 2
},
{
"_id" : {
"min" : 3.0,
"max" : 5.0
},
"count" : 2
},
...중략
]
}
$lookup
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
서로 다른 컬렉션의 정보를 합칠 수 있는 스테이지다. 관계형 데이터베이스의 JOIN 개념과 비슷하다.
shell에서 $lookup을 사용할 때의 전제 조건은, 두 컬렉션이 같은 DB에 있어야 하며, 샤딩되어 있지 않아야 한다.
mogoose와 같은 ODM은 populate라는 메서드로 $lookup을 대체하고 있으니 ODM을 사용할 때는 populate를 사용하면 된다.
$lookup은 다른 두 가지 형식이 있는데 3.6 버전 이상이면 둘 다 쓸 수 있다. 상황에 적절한 것을 이용하면 된다.
New in version 3.2.
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
아래와 같이 작성하면 by_month의 area_id와 area의 _id를 연결합니다. 당연히 이 두 _id는 같은 값이겠죠?
// by_month 컬렉션
db.by_month.aggregate(
[
{$lookup: {
from: "area", // by_month 컬렉션에서 area 컬렉션을 조인합니다.
localField: "area_id", // by_month 컬렉션에서 연결할 필드명
foreignField: "_id", // area 컬렉션에서 연결할 필드명
as: "area_data" // 결과 출력시 보여줄 필드 이름
}},
{$limit: 1}
]
)
결과
{
"_id" : ObjectId("5c8909190da47a8507755fd8"),
"city_or_province" : "서울",
"county" : "종로구",
"area_id" : ObjectId("5c88f9f70da47a8507752775"),
.. 중략
// as에서 설정한 필드 명으로 불러온 area 필드
"area_data" : [
{
"_id" : ObjectId("5c88f9f70da47a8507752775"),
"city_or_province" : "서울",
"county" : "종로구",
"population" : 152737
}
]
}
New in version 3.6.
3.2 버전보다 조금 더 강력한 $lookup입니다.
{
$lookup:
{
from: <collection to join>,
let: { <var_1>: <expression>, …, <var_n>: <expression> }, // optional.
pipeline: [ <pipeline to execute on the collection to join> ],
as: <output array field>
}
}
$replaceRoot
$sample
$sortByCount
'DB, ORM > 🍃 mongoDB (shell)' 카테고리의 다른 글
인덱스 (2) 인덱스 명령어 (0) | 2020.07.25 |
---|---|
인덱스 (1) 인덱싱의 이해, 종류, B-Tree 자료구조 (0) | 2020.07.25 |
집계 명령어 활용하기 (3) Aggregate 파이프라인 (i) 👨🏫 기본적인 stage (0) | 2020.07.24 |
집계 명령어 활용하기 (1) 몽고 DB의 아키텍쳐와 집계의 효율성 (0) | 2020.07.24 |
projection 연산자 (0) | 2020.07.24 |