집계 파이프라인의 개별 단계는 데이터 처리 단위
한번에 입력 도큐먼트 스트림을 하나씩 가져 온 다음, 각 도큐먼트를 하나씩 처리하고, 출력 도큐먼트 스트림을 하나씩 생성한다.
각 단계에는 knobs 또는 tunables 셋을 제공한다.
이 항목들을 조정해 각 단계를 매개변수로 지정함으로써 원하는 작업을 수행할 수 있다.
사용 중인 특정 컬렉션과 도큐먼트에 수행할 작업에 따라 단계를 매개변수화한다.
tunables는 필드를 수정, 산술 연산, 도큐먼트 재구성, 누산 작업 등 연산자의 형태를 취함
파이프라인은 mongoDB 컬렉션과 함께 작동.
파이프라인은 단계로 구성되며 각 단계는 입력에 서로 다른 데이터 처리 작업을 수행하고, 출력으로 도큐먼트를 생성해 다음 단계로 전달한다.
> db.companies.aggregate([{$match: {founded_year: 2004}}])
> db.companies.find({founded_year: 2004})
// 같은 결과
> db.companies.aggregate([
{$match: {founded_year: 2004}},
{$project: {
_id: 0,
name: 1,
founded_year: 1
}}
])
>> {"name": "이름1", "founded_year": 2004}
{"name": "이름2", "founded_year": 2004}
{"name": "이름3", "founded_year": 2004}
{"name": "이름4", "founded_year": 2004}
{"name": "이름5", "founded_year": 2004}
{"name": "이름6", "founded_year": 2004}
{"name": "이름7", "founded_year": 2004}
{"name": "이름8", "founded_year": 2004}
{"name": "이름9", "founded_year": 2004}
aggregate - 집계 쿼리 실행 메소드
각 도큐먼트는 특정 단계 연산자를 규정해야 한다.
위 쿼리는 2개의 단계를 가지고 있다.
위의 쿼리와 동일하게 수행하고, 결과set은 5개로 제한하는 쿼리
> db.companies.aggregate([
{$match: {founded_year: 2004}},
{$limit: 5},
{$project: {
_id: 0,
name: 1,
}}
])
>> {"name": "이름"}
{"name": "이름1"}
{"name": "이름2"}
{"name": "이름3"}
{"name": "이름4"}
> db.companies.aggregate([
{$match: {founded_year: 2004}},
{$project: {
_id: 0,
name: 1,
}},
{$limit: 5}
])
제한을 선출 단계 이전에 수행했을 경우, 결과를 5개로 limit하기 이전에 선출 단계를 통해 선출 조건에 맞는 도큐먼트 모두를 전달해야 함
파이프라인을 구축할 때 한 단계에서 다른 단계로 전달해야 하는 도큐먼트 수를 반드시 제한하자
> db.companies.aggregate([
{$match: {founded_year: 2004} },
{$sort: {name: 1} },
{$limit: 5}
{$project: {
_id: 0,
name: 1,
}},
])
5개의 도큐먼트를 name의 알파벳 순으로 선출한다.
> db.companies.aggregate([
{$match: {founded_year: 2004} },
{$sort: {name: 1} },
{$skip: 10},
{$limit: 5},
{$project: {
_id: 0,
name: 1,
}},
])
founded_year가 2004인 도큐먼트 찾기name 을 기준으로 오름차순 정렬$skip 의 개수만큼 건너 뜀$limit 만큼 제한name 만 출력되도록 도큐먼트 모양 변경> db.companies.aggregate([
{$match: {"funding_rouds.investments.financial_org.permalink": "greylock"}},
{$project: {
_id: 0,
name: 1,
ipo: "$ipo.pub_year",
valuation: "$ipo.valuation_amount",
funders: "$funding_rouds.investments.financial_org.permalink"
}}
]).pretty(){key1: "value1", key2: "value2", key3: ["elem1", "elem2", "elem3"]}
> $unwind
> {key1: "value1", key2: "value2", key3: "elem1"}
> {key1: "value1", key2: "value2", key3: "elem2"}
> {key1: "value1", key2: "value2", key3: "elem3"}
// $unwind는 입력 도큐먼트에서 배열을 가져오고, 해당 배열의 각 요소에 대한 출력 도큐먼트 생성
> db.companies.aggregate([
{$match: {"funding_rouds.investments.financial_org.permalink": "greylock"}},
{$project: {
_id: 0,
name: 1,
founded_year: 1,
rounds: {$filter: {
input: "$funding_rounds",
as: "rounds",
cond: {$gte: ["$$round.raised_amount", 10000000]}}}
}},
{$match: {"rounds.investments.financial_org.permalink": "greylock"}},
]).pretty()
$filter 연산자는 배열 필드와 함께 작동하도록 설계됐으며 우리가 제공하는 옵션을 지정$filter 의 첫 번째 옵션은 input, 단순 배열 지정
- 누산기는 표현식의 유형이지만 도큐먼트에서 찾은 필드 값으로부터 값을 계산하므로 자체 클래스에서 고려한다.
- $sum(합산), $avg(평균) 등의 작업 가능
- $first, $last 누산기로 간주 - 표현식이 사용된 단계를 통과하는 모든 도큐먼트 값을 고려하기 때문
- $max, $min 도큐먼트 스트림을 고려해 표시되는 값 중 하나만 저장하는 누산기
- $mergeObjects로 여러 도큐먼트를 하나의 도큐먼트로 결합 가능
- 배열용 누산기 - 도큐먼트가 파이프라인을 통과할 때 배열에 값을 $push 가능
- $addToSet, $push 의 차이 - 배열에 중복값 추가되지 않는다.
> db.companies.aggregate([
{$match: {"funding_rounds": {$exists: true, $ne: []}}},
{$project: {
_id: 0,
name: 1,
largest_round: {$max: "$funding_rounds.raised_amount"}
}}
])
>> { "name" : "Wetpaint", "largest_round" : 25000000 }
{ "name" : "Digg", "largest_round" : 28700000 }
{ "name" : "Facebook", "largest_ round": 1500000000 }
{ "name" : "Omnidrive", "largest_round" : 800000 }
{ "name" : "Geni" , "largest_round" : 10000000 }
{ "name" : "Twitter", "largest_round" : 400000000 }
{ "name" : "StumbleUpon", "largest_round" : 17000000 }
{ "name" : "Gizmoz", "largest_round" : 6500000 }
{ "name" : "Scribd", "Largest_round" : 13000000 }
{ "name" : "Slacker", "largest_round" : 40000000 }
{ "name" : "Lala", "Largest_round" : 20000000 }
{ "name" : "eBay", "Largest _round" : 6700000 }
{ "name" : "MeetMoi", "largest_round" : 2575000 }
{ "name" : "Joost", "Largest round" : 45000000 }
{ "name" : "Babe laum" , "largest_round": 13200000 }
{ "name" : "Plaxo", "largest_round" : 9000000 }
{ "name" : "Cisco", "Largest _round" : 2500000 }
{ "name" : "Yahoo!", "largest_round" : 4800000 }
{ "name" : "Powerset", "largest _round" : 12500000 }
{ "name" : "Technorati", "largest_round" : 10520000 }
> db.companies.aggregate([
{$match: {"funding_rounds": {$exists: true, $ne: []}}},
{$project: {
_id: 0,
name: 1,
largest_round: {$sum: "$funding_rounds.raised_amount"}
}}
])
SQL의 group by와 유사한 기능 수행
여러 도큐먼트 값을 집계하고, 집계한 값에 평균 계산 같은 집계 작업 가능
> db.companies.aggregate([
{$group: {
_id: { founded_year: "$founded_year" },
average_number_of_employees: {$avg: "$number_of_employess" }
}},
{$sort: { average_number_of_employees: -1 }}
])
founded_year 기준으로 모든 회사를 합친 연도마다 평균 직원 수를 계산
_id 로 grouping
> db.companies.aggregate([
{$match: { founded_year: { $gte: 2013} } },
{$group: {
_id: {founded_year: "$founded_year"},
companies: {$push: "$name"}
}},
{$sort: { "_id.founded_year": 1} }
]).pretty()
_id와 companies라는 필드가 있는 도큐먼트가 있다._id내에 founded_year내에 필드를 넣은 이유> db.companies.aggregate([
{$match: { founded_year: { $gte: 2010} } },
{$group: {
_id: {founded_year: "$founded_year"},
category_code: "$category_code"},
companies: {$push: "$name"}
}},
{$sort: { "_id.founded_year": 1} }
]).pretty()
_id값으로 사용하면 문제 없다.> db.companies.aggregate([
{$match: { founded_year: { $gte: 2010} } },
{$group: {
_id: {ipo_year: "$ipo.ipo_year"},
companies: {$push: "$name"}
}},
{$sort: { "_id.ipo_year": 1} }
]).pretty()
ipo_year기준으로 도큐먼트 그룹화 - 내장 도큐먼트 필드$push$push표현식이 배열에 추가한다.db.companies.aggregate([
{$match: { "relationships": {$ne: null} } },
{$project: { relationships: 1, _id:0 } },
{$unwind: "$relationships" },
{$group: {
_id: "$relationships.person",
count: {$sum:1 }
}},
{$sort: { count: -1 }}
]}> db.companies.aggregate([
{$match: { funding_rounds: {$ne: []} } },
{$unwind: "$funding_rounds" },
{$sort: { "funding_rounds.funded_year": 1,
"funding_rounds.funded_month": 1,
"funding_rounds.funded_day": 1} },
{$group: {
_id: {company: "$name"},
funding: {
$push: {
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
}}
}},
]).pretty()
funding_rounds 배열이 비어있지 않은 도큐먼트를 필터링한다.funding_rounds 전개funding_rounds 배열의 각 요소에 대해 도큐먼트가 표시된다.funding_rounds 부터 출력한다.$push 누산기를 통해 정렬된 funding_rounds 배열을 구성>>
{
"_id": {
$push를 사용해 배열 누적$push 표현식은 그룹 단계에서만 작동db.companies.aggregate([
{ $match: { funding_rounds: { $exists: true, $ne: [ ] }} },
{ $unwind: "$funding_rounds" },
{ $sort: { "funding_rounds.funded_year": 1,
"funding_rounds.funded_month": 1,
"funding_rounds.funded_day": 1} },
{$group: {
_id: { company: "$name" },
first_round: { $first: "$funding_rounds" },
last_round: { $last: "$funding_rounds"},
num_rounds: { $sum: 1},
total_raised: { $sum: "$funding_rounds.raised_amount" }
} },
{ $project: {
_id:0,
company: "$_id.company",
first_round: {
amount: "$first_round.raised_amount",
article: "$first_round.source_url",
year: "$first_round.funded_year"
},
last_round: {
amount: "$last_round.raised_amount",
article: "$alst_round.source_url",
year: "$last_round.funded_year"
},
num_rounds: 1,
total_raised: 1,
} },
{ $sort: { total_raised: -1 } }
]).pretty()
funding_rounds를 전개하고 시간 순으로 정렬funding_rounds를 나타내는 배열의 항목을 누적하는 대신 $first와 $last라는 누산기 사용$first표현식은 단계의 입력 스트림을 통과하는 첫 번째 값을 저장$last 는 그룹 단계를 통과한 마지막 값을 추적$push $first $last 사용X$out $merge - 둘 중 하나, 마지막 단계$merge mongoDB 4.2 도입 - 쓰기 단계에서 선호$out$merge