개요
MongoDB에서 집계(aggregate) 파이프라인의 $group 단계와 $addToSet 연산자를 함께 사용하면, 하나의 쿼리만으로 데이터를 그룹화하는 동시에 특정 필드의 고유값(distinct)을 추출할 수 있습니다. 아래 예제에서는 학생 데이터를 대상으로 이름과 반(section)의 고유값을 구하고, 나이와 점수의 최솟값·최댓값까지 한 번에 계산하는 방법을 살펴보겠습니다.
1. 샘플 컬렉션 생성
먼저 insertOne() 메서드를 사용하여 문서가 포함된 컬렉션을 생성합니다.
> db.demo16.insertOne({
... "StudentName" : "Chris",
... "StudentSection" : "A",
... "StudentAge" : 23,
... "StudentMarks" : 47
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5e13827455d0fc6657d21f07")
}
> db.demo16.insertOne({
... "StudentName" : "Bob",
... "StudentSection" : "B",
... "StudentAge" : 21,
... "StudentMarks" : 85
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5e13827555d0fc6657d21f08")
}
> db.demo16.insertOne({
... "StudentName" : "Carol",
... "StudentSection" : "A",
... "StudentAge" : 26,
... "StudentMarks" : 97
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5e13827655d0fc6657d21f09")
}2. 전체 문서 조회
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다.
> db.demo16.find().pretty();
실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e13827455d0fc6657d21f07"),
"StudentName" : "Chris",
"StudentSection" : "A",
"StudentAge" : 23,
"StudentMarks" : 47
}
{
"_id" : ObjectId("5e13827555d0fc6657d21f08"),
"StudentName" : "Bob",
"StudentSection" : "B",
"StudentAge" : 21,
"StudentMarks" : 85
}
{
"_id" : ObjectId("5e13827655d0fc6657d21f09"),
"StudentName" : "Carol",
"StudentSection" : "A",
"StudentAge" : 26,
"StudentMarks" : 97
}3. 그룹화와 Distinct를 동시에 수행하는 쿼리
aggregate() 파이프라인에서 $group 단계를 구성할 때 _id를 null로 지정하면 전체 문서가 하나의 그룹으로 묶입니다. 이 상태에서 $addToSet을 사용하면 해당 필드의 중복이 제거된 고유값 목록(배열)을 얻을 수 있으며, $min과 $max를 활용하면 최솟값과 최댓값도 함께 계산됩니다.
> db.demo16.aggregate([{
... $group : {
... _id : null,
... StudentName : { $addToSet : "$StudentName" },
... StudentSection : { $addToSet : "$StudentSection" },
... StudentMinimumAge : { $min : "$StudentAge" },
... StudentMaximumAge : { $max : "$StudentAge" },
... StudentMinimumMarks: { $min : "$StudentMarks" },
... StudentMaximumMarks : { $max : "$StudentMarks" }
... }
... }]).pretty();위 쿼리의 실행 결과는 다음과 같습니다.
{
"_id" : null,
"StudentName" : [
"Carol",
"Bob",
"Chris"
],
"StudentSection" : [
"B",
"A"
],
"StudentMinimumAge" : 21,
"StudentMaximumAge" : 26,
"StudentMinimumMarks" : 47,
"StudentMaximumMarks" : 97
}결과 해석
- StudentName: 중복 없이 모든 학생 이름(Carol, Bob, Chris)이 배열 형태로 반환됩니다.
- StudentSection: A반과 B반, 두 개의 고유한 값만 추출됩니다.
- StudentMinimumAge / StudentMaximumAge: 학생 나이의 최솟값(21)과 최댓값(26)이 계산됩니다.
- StudentMinimumMarks / StudentMaximumMarks: 점수의 최솟값(47)과 최댓값(97)이 계산됩니다.
이처럼 $group과 $addToSet을 조합하면 별도의 distinct 쿼리를 추가로 실행하지 않고도, 단일 집계 쿼리 안에서 그룹 통계 산출과 고유값 추출을 동시에 처리할 수 있습니다. 대량의 데이터를 다룰 때 여러 번의 쿼리 왕복을 줄여 성능 면에서도 유리합니다.