$group (집계)
정의
$group
$group 스테이지는 그룹 키에 따라 동일한 필드, 필드들 또는 표현식을 가진 여러 문서를 단일 문서로 결합합니다. 결과는 고유한 그룹 키당 하나의 문서입니다.
그룹 키는 종종 필드 또는 필드 그룹입니다. 그룹 키는 어떤 표현식의 결과일 수도 있습니다. 그룹 키는
$group
파이프라인 단계의_id
필드를 사용해 설정할 수 있습니다. 사용 예시는 아래를 참조하세요.$group
단계 출력에서_id
필드는 해당 문서의 그룹 키로 설정됩니다.출력 문서에는 축적자 표현식을 사용하여 설정한 추가 필드도 포함될 수 있습니다.
참고
$group
은 출력 문서의 순서를 지정하지 않습니다.
호환성
다음 환경에서 호스팅되는 배포에 $group
사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
$group
단계의 프로토타입 형식은 다음과 같습니다.
{ $group: { _id: <expression>, // Group key <field1>: { <accumulator1> : <expression1> }, ... } }
필드 | 설명 |
---|---|
| 필수입니다. |
| 선택 사항. 축적자 자 연산자를 사용하여 계산됩니다. |
_id
및 누산기 연산자는 유효한 expression
을 모두 허용할 수 있습니다. 표현식에 대한 자세한 내용은 표현식 연산자를 참조하세요.
고려 사항
성능
$group
은(는) 차단 단계로, 파이프라인 이 데이터를 처리 하기 전에 차단 단계의 모든 입력 데이터가 검색될 때까지 대기하도록 합니다. 차단 단계는 여러 단계로 구성된 파이프라인 의 병렬 처리 를 줄이기 때문에 성능이 저하될 수 있습니다. 차단 단계는 대규모 데이터 세트에 상당한 양의 메모리를 사용할 수도 있습니다.
누산기 연산자
<accumulator>
연산자는 다음 누산기 연산자 중 하나이어야 합니다.
버전 5.0에서 변경됨
이름 | 설명 |
---|---|
사용자 정의 누산기 함수의 결과를 반환합니다. | |
각 그룹에 대한 고유한 표현식 값의 배열을 반환합니다. 배열 요소의 순서가 정의되지 않았습니다. 버전 5.0에서 변경: | |
숫자 값의 평균을 반환합니다. 숫자가 아닌 값을 무시합니다. 버전 5.0에서 변경: | |
지정된 정렬 순서에 따라 그룹 내 하위 개 요소의 집계를 반환합니다. 버전 5.2에 추가되었습니다. 2} 및 단계에서 | |
그룹에 있는 문서 수를 반환합니다.
버전 5.2의 새로운 기능: | |
그룹의 첫 번째 문서에 대한 표현식 결과를 반환합니다. 버전 5.0에서 변경: | |
그룹 내 첫 버전 5.2의 새로운 기능: | |
그룹의 마지막 문서에 대한 표현식의 결과를 반환합니다. 버전 5.0에서 변경: | |
그룹 내 마지막 버전 5.2의 새로운 기능: | |
각 그룹에 대해 가장 높은 표현식 값을 반환합니다. 버전 5.0에서 변경: | |
그룹 내 최댓값을 가진 개 요소의 집계를 반환합니다. 버전 5.2에 추가되었습니다. | |
각 그룹에 대한 입력 문서를 결합하여 생성된 문서를 반환합니다. | |
각 그룹에 대해 가장 낮은 표현식 값을 반환합니다. 버전 5.0에서 변경: | |
그룹 내 최솟값을 가진 개 요소의 집계를 반환합니다. 버전 5.2에 추가되었습니다. | |
각 그룹의 문서에 대한 표현식 값의 배열을 반환합니다. 버전 5.0에서 변경: | |
입력 값의 모집단 표준 편차를 반환합니다. 버전 5.0에서 변경: | |
입력 값의 표본 표준 편차를 반환합니다. 버전 5.0에서 변경: | |
숫자 값의 합계를 반환합니다. 숫자가 아닌 값을 무시합니다. 버전 5.0에서 변경: | |
지정된 정렬 순서에 따라 그룹 내 상위 개 요소의 집계를 반환합니다. 버전 5.2에 추가되었습니다. 2} 및 단계에서 |
$group
및 메모리 제한
$group
단계가 100MB의 RAM을 초과하면 MongoDB는 임시 파일에 데이터를 씁니다. 그러나 allowDiskUse 옵션이 false
로 설정되어 있으면 $group
은 오류를 반환합니다. 자세한 내용은 집계 파이프라인 제한을 참조하세요.
$group
성능 최적화
이 섹션에서는 $group
의 성능을 개선하기 위한 최적화에 대해 설명합니다. 수동으로 수행할 수 있는 최적화와 MongoDB가 내부적으로 수행할 수 있는 최적화가 있습니다.
각 그룹의 첫 번째 또는 마지막 문서 반환 최적화
파이프라인이 동일한 필드를 기준으로 sorts
(정렬) 및 groups
(그룹화)를 수행하고, $group
단계에서 $first
또는 $last
누산기 연산자만 사용하는 경우 정렬 순서와 일치하는 그룹화된 필드에 인덱스 를 추가하는 것이 좋습니다. 어떤 경우에는 $group
단계에서 인덱스를 사용하여 각 그룹의 첫 번째 또는 마지막 문서를 빠르게 찾을 수 있습니다.
예시
foo
이라는 컬렉션에 { x: 1, y: 1 }
인덱스가 포함된 경우 다음 파이프라인은 해당 인덱스를 사용하여 각 그룹의 첫 번째 문서를 찾을 수 있습니다.
db.foo.aggregate([ { $sort:{ x : 1, y : 1 } }, { $group: { _id: { x : "$x" }, y: { $first : "$y" } } } ])
슬롯 기반 쿼리 실행 엔진
참고
버전 7.0.17부터 7.0의 패치 버전에 대해 슬롯 기반 쿼리 실행 엔진 더 이상 기본값 으로 활성화되지 않습니다. 쿼리에서 슬롯 기반 쿼리 실행 엔진 사용하려면 기본값 으로 활성화되어 있는 버전 8.0으로 업그레이드 하세요.
버전 5.2부터는 다음 중 하나에 해당하는 경우 MongoDB가 슬롯 기반 실행 쿼리 엔진을 사용해 $group
단계를 실행합니다.
$group
은(는) 파이프라인의 첫 번째 단계입니다.파이프라인의 모든 이전 단계는 슬롯 기반 실행 엔진에 의해 실행될 수도 있습니다.
자세한 내용은 $group
최적화를 참조하세요.
예시
컬렉션 내의 문서 수 계산
mongosh
에서 다음 문서를 사용하여 sales
라는 이름의 샘플 컬렉션을 만듭니다.
db.sales.insertMany([ { "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") }, { "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") }, { "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") }, { "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") }, { "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") }, { "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") }, { "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") }, { "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") }, ])
다음 집계 작업은 $group
단계를 사용하여 sales
컬렉션의 문서 수를 계산합니다.
db.sales.aggregate( [ { $group: { _id: null, count: { $count: { } } } } ] )
이 연산은 다음과 같은 결과를 반환합니다.
{ "_id" : null, "count" : 8 }
이 집계 작업은 다음 SQL 문과 동일합니다.
SELECT COUNT(*) AS count FROM sales
다음도 참조하세요.
Retrieve Distinct Values
다음 집계 연산은 $group
단계를 사용하여 sales
컬렉션에서 고유 항목 값을 조회합니다.
db.sales.aggregate( [ { $group : { _id : "$item" } } ] )
이 연산은 다음과 같은 결과를 반환합니다.
{ "_id" : "abc" } { "_id" : "jkl" } { "_id" : "def" } { "_id" : "xyz" }
참고
$group
를 사용하여 샤딩된 컬렉션 에서 고유 값을 조회 할 때 작업 결과 가 발생하면 결과에 DISTINCT_SCAN
고아 문서가포함될 수 있습니다.
영향을 받는 유일한 의미론적으로 올바른 파이프라인 distinct
$group
파이프라인 시작 부분에 단계가 있고 앞에 단계가 없는 명령과 사실상 논리적으로 $group
$sort
동일합니다. .
예시 들어, 다음 형식의 $group
연산은 DISTINCT_SCAN
이(가) 발생할 수 있습니다.
{ $group : { _id : "$<field>" } }
고유 값을 검색하기 위한 동작에 대한 자세한 내용은 고유 명령 동작을 참조하세요.
작업 결과가 인지 DISTINCT_SCAN
확인하려면작업의 설명 결과를 확인하세요.
항목별 그룹화
다음 집계 작업은 item
필드를 기준으로 문서를 그룹화하여 품목당 총 판매 금액을 계산하고 총 판매 금액이 100 이상인 품목만 반환합니다.
db.sales.aggregate( [ // First Stage { $group : { _id : "$item", totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } } } }, // Second Stage { $match: { "totalSaleAmount": { $gte: 100 } } } ] )
- 첫 번째 단계:
$group
단계는 고유 항목 값을 검색하기 위해 문서를item
으로 그룹화합니다. 이 단계에서는 각 항목에totalSaleAmount
를 반환합니다.- 두 번째 단계:
$match
단계는 결과 문서를 필터링하여totalSaleAmount
이(가) 100보다 크거나 같은 항목만 반환합니다.
이 연산은 다음과 같은 결과를 반환합니다.
{ "_id" : "abc", "totalSaleAmount" : Decimal128("170") } { "_id" : "xyz", "totalSaleAmount" : Decimal128("150") } { "_id" : "def", "totalSaleAmount" : Decimal128("112.5") }
이 집계 작업은 다음 SQL 문과 동일합니다.
SELECT item, Sum(( price * quantity )) AS totalSaleAmount FROM sales GROUP BY item HAVING totalSaleAmount >= 100
다음도 참조하세요.
개수, 합계 및 평균 계산
mongosh
에서 다음 문서를 사용하여 sales
라는 이름의 샘플 컬렉션을 만듭니다.
db.sales.insertMany([ { "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") }, { "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") }, { "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") }, { "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") }, { "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") }, { "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") }, { "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") }, { "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") }, ])
한 해의 날짜별로 그룹화하기
다음 파이프라인은 2014년 한 해 동안의 총 판매 금액, 평균 판매량 및 일일 판매 횟수를 계산합니다.
db.sales.aggregate([ // First Stage { $match : { "date": { $gte: new ISODate("2014-01-01"), $lt: new ISODate("2015-01-01") } } }, // Second Stage { $group : { _id : { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }, averageQuantity: { $avg: "$quantity" }, count: { $sum: 1 } } }, // Third Stage { $sort : { totalSaleAmount: -1 } } ])
- 첫 번째 단계:
$match
단계는 2014년에 작성된 문서만 다음 단계로 전달하도록 문서를 필터링합니다.- 두 번째 단계:
$group
단계에서는 문서를 날짜별로 그룹화하고 각 그룹에 있는 문서의 총 판매 금액, 평균 수량 및 총 개수를 계산합니다.- 세 번째 단계:
$sort
단계는 각 그룹의 총 판매 금액을 기준으로 결과를 내림차순으로 정렬합니다.
이 연산은 다음과 같은 결과를 반환합니다.
{ "_id" : "2014-04-04", "totalSaleAmount" : Decimal128("200"), "averageQuantity" : 15, "count" : 2 } { "_id" : "2014-03-15", "totalSaleAmount" : Decimal128("50"), "averageQuantity" : 10, "count" : 1 } { "_id" : "2014-03-01", "totalSaleAmount" : Decimal128("40"), "averageQuantity" : 1.5, "count" : 2 }
이 집계 작업은 다음 SQL 문과 동일합니다.
SELECT date, Sum(( price * quantity )) AS totalSaleAmount, Avg(quantity) AS averageQuantity, Count(*) AS Count FROM sales WHERE date >= '01/01/2014' AND date < '01/01/2015' GROUP BY date ORDER BY totalSaleAmount DESC
다음도 참조하세요.
db.collection.countDocuments()
(은)는$group
집계 단계를$sum
표현식으로 래핑합니다.
null
으로 그룹화
다음 집계 작업은 null
의 그룹 _id
을(를) 지정하여 collection의 총 판매 금액, 평균 수량 및 모든 문서의 개수를 계산합니다.
db.sales.aggregate([ { $group : { _id : null, totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }, averageQuantity: { $avg: "$quantity" }, count: { $sum: 1 } } } ])
이 연산은 다음과 같은 결과를 반환합니다.
{ "_id" : null, "totalSaleAmount" : Decimal128("452.5"), "averageQuantity" : 7.875, "count" : 8 }
이 집계 작업은 다음 SQL 문과 동일합니다.
SELECT Sum(price * quantity) AS totalSaleAmount, Avg(quantity) AS averageQuantity, Count(*) AS Count FROM sales
다음도 참조하세요.
db.collection.countDocuments()
(은)는$group
집계 단계를$sum
표현식으로 래핑합니다.
Pivot Data
mongosh
에서 다음 문서를 사용하여 books
라는 이름의 샘플 컬렉션을 만듭니다.
db.books.insertMany([ { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }, { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }, { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }, { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }, { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } ])
author
별로 title
그룹화
다음 집계 작업은 books
collection의 데이터를 피봇하여 작성자별로 제목을 그룹화합니다.
db.books.aggregate([ { $group : { _id : "$author", books: { $push: "$title" } } } ])
이 작업은 다음 문서를 반환합니다.
{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] } { "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }
author
별로 문서 그룹화
다음 집계 작업은 author
를 기준으로 문서를 그룹화합니다.
db.books.aggregate([ // First Stage { $group : { _id : "$author", books: { $push: "$$ROOT" } } }, // Second Stage { $addFields: { totalCopies : { $sum: "$books.copies" } } } ])
- 첫 번째 단계:
$group
은$ROOT
시스템 변수를 사용하여 전체 문서를 작성자별로 그룹화합니다. 이 단계에서는 다음 문서를 다음 단계로 전달합니다.{ "_id" : "Homer", "books" : [ { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }, { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } ] }, { "_id" : "Dante", "books" : [ { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }, { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }, { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 } ] } - 두 번째 단계:
$addFields
은(는) 각 저자의 총 도서 사본 수를 포함하는 필드를 출력에 추가합니다.참고
결과 문서는 BSON 문서 크기 제한인 16메비바이트를 초과할 수 없습니다.
이 작업은 다음 문서를 반환합니다.
{ "_id" : "Homer", "books" : [ { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }, { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } ], "totalCopies" : 20 } { "_id" : "Dante", "books" : [ { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }, { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }, { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 } ], "totalCopies" : 5 }
다음도 참조하세요.
추가 리소스
우편번호 데이터 세트를 사용한 집계 튜토리얼에서는 $group
연산자에 관한 광범위한 일반 사용 사례 예시를 설명합니다.