MongoDB 집계로 여러 필드 기준 개수 세기
여러 필드를 기준으로 문서 수를 집계하려면 MongoDB의 $facet 연산자를 활용하면 됩니다. $facet은 단일 단계(single stage) 안에서 동일한 입력 문서 집합에 대해 여러 개의 집계 파이프라인을 동시에 처리할 수 있게 해주는 강력한 기능입니다.
먼저 예제에 사용할 컬렉션을 생성하고 문서를 삽입해 보겠습니다.
> db.demo721.insertOne(
... {
... "details1": {
... "id":101
... },
... "details2": {
... "id":101
... },
... "details3": {
... "id":101
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5eaaebdd43417811278f5887")
}
>
>
> db.demo721.insertOne(
... {
... "details1": {
... "id":101
... },
... "details2": {
... "id":102
... },
... "details3": {
... "id":102
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5eaaebe943417811278f5888")
}
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다.
> db.demo721.find();
위 명령을 실행하면 다음과 같은 결과가 출력됩니다.
{ "_id" : ObjectId("5eaaebdd43417811278f5887"), "details1" : { "id" : 101 }, "details2" : { "id" : 101 }, "details3" : { "id" : 101 } }
{ "_id" : ObjectId("5eaaebe943417811278f5888"), "details1" : { "id" : 101 }, "details2" : { "id" : 102 }, "details3" : { "id" : 102 } }여러 필드 기준 카운트 쿼리 작성하기
다음은 여러 필드를 기준으로 개수를 집계하는 쿼리입니다. 이 쿼리는 크게 두 단계로 동작합니다. 먼저 $facet 내부에서 두 개의 하위 파이프라인을 실행하는데, 하나는 $addToSet과 $setUnion을 이용해 모든 details 필드에 등장하는 고유 id 값을 수집하고, 다른 하나는 각 문서에서 details1.id, details2.id, details3.id 값만 추출합니다. 이후 $unwind로 배열을 풀어낸 뒤, $group과 $cond 조건식을 조합하여 각 id가 각 필드별로 몇 번 등장했는지 합산합니다.
> db.demo721.aggregate([
... {$facet:{
... ids:[
... {$group:{ _id:null,
... d3:{$addToSet: "$details3.id"},
... d2:{$addToSet:"$details2.id"},
... d1:{$addToSet:"$details1.id"}}},
... {$project:{ _id:0,
... listofall:{$setUnion:["$d1","$d2","$d3"]}}}],
... d:[{$project:{ _id:0,
... a1:"$details1.id",
... a2:"$details2.id",
... a3:"$details3.id"}}]}},
... {$unwind:"$d"},
... {$unwind:"$ids"},
... {$unwind:"$ids.listofall"},
... {$group:{ _id:"$ids.listofall",
... details1id:{$sum:{$cond:[{$eq:["$d.a1","$ids.listofall"]},1,0]}},
... details2id:{$sum:{$cond:[{$eq:["$d.a2","$ids.listofall"]},1,0]}},
... details3id:{$sum:{$cond:[{$eq:["$d.a3","$ids.listofall"]},1,0]}}}}])
쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{ "_id" : 102, "details1id" : 0, "details2id" : 1, "details3id" : 1 }
{ "_id" : 101, "details1id" : 2, "details2id" : 1, "details3id" : 1 }결과 해석
출력 결과를 보면 id 101은 details1 필드에서 2번, details2와 details3 필드에서 각각 1번씩 등장했습니다. 반면 id 102는 details1에는 전혀 없었고(0), details2와 details3에서 각각 1번씩 나타났습니다. 이처럼 $facet을 활용하면 여러 필드에 흩어진 값을 한 번의 집계 파이프라인으로 손쉽게 비교·카운트할 수 있습니다.