문서 메뉴
문서 홈
/
MongoDB 매뉴얼
/ / /

어큐뮬레이터(집계)

이 페이지의 내용

  • 정의
  • 구문
  • 행동
  • 예제
$accumulator

사용자 지정 축적자 연산자 를 정의합니다. 축적자는 문서가 파이프라인을 통과할 때 상태(예: 합계, 최대값, 최소값 및 관련 데이터)를 유지하는 연산자입니다. $accumulator 연산자를 사용하여 자체 JavaScript 함수를 실행하여 MongoDB 쿼리 언어에서 지원하지 않는 동작을 구현합니다. $function 도 참조하세요.

$accumulator 이 단계에서 사용할 수 있습니다:

중요

애그리게이션 연산자 내에서 JavaScript를 실행하면 성능이 저하될 수 있습니다. 제공된 파이프라인 $accumulator 연산자 가 애플리케이션의 요구 사항을 충족할 수 없는 경우에만 연산자를 사용합니다.

$accumulator 연산자의 구문은 다음과 같습니다.

{
$accumulator: {
init: <code>,
initArgs: <array expression>, // Optional
accumulate: <code>,
accumulateArgs: <array expression>,
merge: <code>,
finalize: <code>, // Optional
lang: <string>
}
}
필드
유형
설명
init
문자열 또는 코드

상태를 초기화하는 데 사용되는 함수입니다. init 함수는 initArgs 배열 표현식에서 인수를 받습니다. 함수 정의를 BSON type 코드 또는 문자열로 지정할 수 있습니다.

init 함수의 형식은 다음과 같습니다.

function (<initArg1>, <initArg2>, ...) {
...
return <initialState>
}

참고

디스크로 유출하거나 샤드 클러스터에서 쿼리를 실행하면 축적자가 각각 init()을(를) 호출하여 시작하는 여러 하위 누적의 병합으로 계산될 수 있습니다. init(), accumulate()merge() 함수가 이 실행 모델과 호환되는지 확인합니다.

배열

선택 사항. init 함수에 전달된 인수입니다.

initArgs 의 형식은 다음과 같습니다.

[ <initArg1>, <initArg2>, ... ]

중요

$bucketAuto단계에서 사용되는 경우 initArgs는 그룹 키를 참조할 수 없습니다(즉, $<fieldName> 구문을 사용할 수 없음). 대신 $bucketAuto 단계에서는 initArgs에 상수 값만 지정할 수 있습니다.

문자열 또는 코드

문서를 누적하는 데 사용되는 함수입니다. accumulate 함수는 현재 상태 및 aggregateArgs 배열 표현식에서 인수를 받습니다. accumulate 함수의 결과는 새 상태가 됩니다. 함수 정의를 BSON type 코드 또는 문자열로 지정할 수 있습니다.

accumulate 함수의 형식은 다음과 같습니다.

function(state, <accumArg1>, <accumArg2>, ...) {
...
return <newState>
}
배열

accumulate 함수에 전달된 인수입니다. accumulateArgs을 사용하여 accumulate 함수에 전달할 필드 값을 지정할 수 있습니다.

accumulateArgs 의 형식은 다음과 같습니다.

[ <accumArg1>, <accumArg2>, ... ]
문자열 또는 코드

두 개의 내부 상태를 병합하는 데 사용되는 함수입니다. merge 은(는) 문자열 또는 코드 BSON 유형이어야 합니다. merge 은 병합된 두 상태의 결합된 결과를 반환합니다. 병합 함수가 호출되는 경우에 대한 자세한 내용은 $merge 로 두 가지 상태 병합 항목을 참조하세요.

merge 함수의 형식은 다음과 같습니다.

function (<state1>, <state2>) {
<logic to merge state1 and state2>
return <newState>
}
문자열 또는 코드

선택 사항. 누적 결과를 업데이트하는 데 사용되는 함수입니다.

finalize 함수의 형식은 다음과 같습니다.

function (state) {
...
return <finalState>
}
문자열

$accumulator 코드에 사용된 언어입니다.

중요

현재 lang에 대해 지원되는 유일한 값은 js입니다.

다음 단계에서는 $accumulator 연산자가 문서를 처리하는 방법을 간략하게 설명합니다.

  1. 연산자는 init 함수에 의해 정의된 초기 상태에서 시작됩니다.

  2. 각 문서에 대해 연산자는 누적 함수를 기반으로 상태를 업데이트합니다. 누적 함수의 첫 번째 인수는 현재 상태이며 추가 인수는 accumulateArgs 배열에 지정할 수 있습니다.

  3. 연산자는 여러 중간 상태를 병합해야 하는 경우 병합 함수를 실행합니다. 병합 함수가 호출되는 경우에 대한 자세한 내용은 $merge 로 두 가지 상태 병합 항목을 참조하세요.

  4. finalize 함수가 정의되어 있는 경우 모든 문서가 처리되고 그에 따라 상태가 업데이트되면 finalize 함수가 상태를 최종 출력으로 변환합니다.

내부 연산의 일부로 $accumulator 연산자는 두 개의 개별적인 중간 상태를 병합해야 할 수 있습니다. 병합 함수는 연산자가 두 상태를 병합하는 방법을 지정합니다.

병합 함수는 항상 한 번에 두 가지 상태를 병합합니다. 세 개 이상의 상태를 병합해야 하는 경우 두 상태의 결과 병합은 단일 상태로 병합됩니다. 이 프로세스는 모든 상태가 병합될 때까지 반복됩니다.

예를 들어 $accumulator 는 다음 시나리오에서 두 상태를 결합해야 할 수 있습니다.

  • $accumulator 샤드 클러스터에서 실행됩니다. 연산자는 최종 결과를 얻기 위해 각 샤드의 결과를 병합해야 합니다.

  • 단일 $accumulator 작업이 지정된 메모리 제한을 초과했습니다. allowDiskUse 옵션을 지정하면 연산자는 진행 중인 작업을 디스크에 저장하고 메모리에서 작업을 완료합니다. 작업이 완료되면 병합 기능을 사용하여 디스크와 메모리의 결과를 함께 병합합니다.

MongoDB가 init(), accumulate()merge() 함수에 대한 문서를 처리하는 순서는 다를 수 있으며 $accumulator 함수에 해당 문서가 지정된 순서와 다를 수 있습니다.

예를 들어 _id 필드가 알파벳 문자인 일련의 문서를 가정해 보겠습니다.

{ _id: 'a' },
{ _id: 'b' },
{ _id: 'c' }
...
{ _id: 'z' }

다음으로, _id 필드를 기준으로 문서를 정렬한 다음 $accumulator 함수를 사용하여 _id 필드 값을 연결하는 집계 파이프라인을 가정해 보겠습니다.

[
{
$sort: { _id: 1 }
},
{
$group: {
_id: null,
alphabet: {
$accumulator: {
init: function() {
return ""
},
accumulate: function(state, letter) {
return(state + letter)
},
accumulateArgs: [ "$_id" ],
merge: function(state1, state2) {
return(state1 + state2)
},
lang: "js"
}
}
}
}
]

MongoDB는 문서가 정렬된 순서로 처리된다고 보장하지 않으므로 alphabet 필드가 반드시 abc...z 로 설정되지는 않습니다.

이 동작으로 인해 $accumulator 함수가 특정 순서로 문서를 처리하고 반환할 필요가 없는지 확인합니다.

$accumulator 을(를) 사용하려면 서버 측 스크립팅을 활성화해야 합니다.

$accumulator (또는 $function, $where 또는 mapReduce)를 사용하지 않는 경우 서버 측 스크립팅을 비활성화합니다.

또한 ➤ 보안 구성 옵션으로 MongoDB 실행을 참조하세요.

MongoDB 6.0 는 서버 측 JavaScript, $accumulator, $function$where 표현식에 사용되는 내부 JavaScript 엔진을 MozJS-60 에서 MozJS-91 로 업그레이드합니다. MozJS-60 에 존재했던 사용 중단된 몇 가지 비표준 배열과 문자열 함수가 MozJS-91 에서 제거되었습니다.

제거된 배열 및 문자열 함수의 전체 목록은 6.0 호환성 정보를 참조하십시오.

참고

이 예제에서는 $accumulator 연산자를 사용하여 MongoDB에서 이미 지원되는 $avg 연산자를 구현하는 방법을 안내합니다. 이 예제의 목표는 새로운 기능을 구현하는 것이 아니라 $accumulator 연산자의 동작과 구문을 익숙한 논리로 설명하는 것입니다.

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 로 문서를 groups 하고 $accumulator 를 사용하여 각 저자의 책에 대한 평균 사본 수를 계산합니다.

db.books.aggregate([
{
$group :
{
_id : "$author",
avgCopies:
{
$accumulator:
{
init: function() { // Set the initial state
return { count: 0, sum: 0 }
},
accumulate: function(state, numCopies) { // Define how to update the state
return {
count: state.count + 1,
sum: state.sum + numCopies
}
},
accumulateArgs: ["$copies"], // Argument required by the accumulate function
merge: function(state1, state2) { // When the operator performs a merge,
return { // add the fields from the two states
count: state1.count + state2.count,
sum: state1.sum + state2.sum
}
},
finalize: function(state) { // After collecting the results from all documents,
return (state.sum / state.count) // calculate the average
},
lang: "js"
}
}
}
}
])

이 연산은 다음과 같은 결과를 반환합니다.

{ "_id" : "Dante", "avgCopies" : 1.6666666666666667 }
{ "_id" : "Homer", "avgCopies" : 10 }

$accumulatorcountsum 가 모두 0 로 설정된 초기 상태를 정의합니다. $accumulator 가 처리하는 각 문서에 대해 다음을 통해 상태를 업데이트합니다.

  • count를 1씩 증가

  • 문서의 copies 필드 값을 sum 에 추가합니다. 누적 함수는 aggregateArgs 필드에 전달되기 때문에 copies 필드에 액세스할 수 있습니다.

문서가 처리될 때마다 accumulate 함수는 업데이트된 상태를 반환합니다.

모든 문서가 처리되면 finalize 함수는 사본의 sum count 로 나누어 평균을 구합니다. 이렇게 하면 finalize 함수가 모든 문서의 누적 sumcount 를 수신하므로 실행 중인 계산된 평균을 계속 유지할 필요가 없습니다.

이 작업은 $avg 연산자를 사용하는 다음 파이프라인과 동일합니다.

db.books.aggregate([
{
$group : {
_id : "$author",
avgCopies: { $avg: "$copies" }
}
}
])

에서 initArgs 옵션을 사용하여 $accumulator 의 초기 상태를 변경할 수 있습니다. 예를 들어 다음과 같은 경우에 유용합니다.

  • 사용자의 상태에 없는 필드 값을 사용하여 사용자의 상태에 영향을 미치거나

  • 처리 중인 그룹에 따라 초기 상태를 다른 값으로 설정합니다.

mongosh 에서 다음 문서를 사용하여 restaurants 라는 이름의 샘플 컬렉션을 만듭니다.

db.restaurants.insertMany([
{ "_id" : 1, "name" : "Food Fury", "city" : "Bettles", "cuisine" : "American" },
{ "_id" : 2, "name" : "Meal Macro", "city" : "Bettles", "cuisine" : "Chinese" },
{ "_id" : 3, "name" : "Big Crisp", "city" : "Bettles", "cuisine" : "Latin" },
{ "_id" : 4, "name" : "The Wrap", "city" : "Onida", "cuisine" : "American" },
{ "_id" : 5, "name" : "Spice Attack", "city" : "Onida", "cuisine" : "Latin" },
{ "_id" : 6, "name" : "Soup City", "city" : "Onida", "cuisine" : "Chinese" },
{ "_id" : 7, "name" : "Crave", "city" : "Pyote", "cuisine" : "American" },
{ "_id" : 8, "name" : "The Gala", "city" : "Pyote", "cuisine" : "Chinese" }
])

사용자가 이 데이터를 쿼리하여 레스토랑을 찾을 수 있는 애플리케이션이 있다고 가정해 보겠습니다. 사용자가 거주하고 있는 도시에 대한 결과를 더 많이 표시하는 것이 유용할 수 있습니다. 이 예제에서는 사용자의 도시가 userProfileCity이라는 변수에서 호출된다고 가정합니다.

다음 집계 파이프라인 groupscity 에 의해 문서를 작성합니다. 이 작업은 $accumulator 를 사용하여 레스토랑의 도시가 사용자 프로필의 도시와 일치하는지 여부에 따라 각 도시에서 다른 수의 결과를 표시합니다.

참고

mongosh 에서 이 예제를 실행하려면 initArgs<userProfileCity> 를 실제 도시 값이 포함된 문자열(예: Bettles)로 바꿉니다.

1db.restaurants.aggregate([
2{
3 $group :
4 {
5 _id : { city: "$city" },
6 restaurants:
7 {
8 $accumulator:
9 {
10 init: function(city, userProfileCity) { // Set the initial state
11 return {
12 max: city === userProfileCity ? 3 : 1, // If the group matches the user's city, return 3 restaurants
13 restaurants: [] // else, return 1 restaurant
14 }
15 },
16
17 initArgs: ["$city", <userProfileCity>], // Argument to pass to the init function
18
19 accumulate: function(state, restaurantName) { // Define how to update the state
20 if (state.restaurants.length < state.max) {
21 state.restaurants.push(restaurantName);
22 }
23 return state;
24 },
25
26 accumulateArgs: ["$name"], // Argument required by the accumulate function
27
28 merge: function(state1, state2) {
29 return {
30 max: state1.max,
31 restaurants: state1.restaurants.concat(state2.restaurants).slice(0, state1.max)
32 }
33 },
34
35 finalize: function(state) { // Adjust the state to only return field we need
36 return state.restaurants
37 }
38
39 lang: "js"
40 }
41 }
42 }
43}
44])

userProfileCity의 값이 Bettles인 경우, 연산은 다음과 같은 결과를 반환합니다.

{ "_id" : { "city" : "Bettles" }, "restaurants" : { "restaurants" : [ "Food Fury", "Meal Macro", "Big Crisp" ] } }
{ "_id" : { "city" : "Onida" }, "restaurants" : { "restaurants" : [ "The Wrap" ] } }
{ "_id" : { "city" : "Pyote" }, "restaurants" : { "restaurants" : [ "Crave" ] } }

userProfileCity의 값이 Onida인 경우, 연산은 다음과 같은 결과를 반환합니다.

{ "_id" : { "city" : "Bettles" }, "restaurants" : { "restaurants" : [ "Food Fury" ] } }
{ "_id" : { "city" : "Onida" }, "restaurants" : { "restaurants" : [ "The Wrap", "Spice Attack", "Soup City" ] } }
{ "_id" : { "city" : "Pyote" }, "restaurants" : { "restaurants" : [ "Crave" ] } }

userProfileCity의 값이 Pyote인 경우, 연산은 다음과 같은 결과를 반환합니다.

{ "_id" : { "city" : "Bettles" }, "restaurants" : { "restaurants" : [ "Food Fury" ] } }
{ "_id" : { "city" : "Onida" }, "restaurants" : { "restaurants" : [ "The Wrap" ] } }
{ "_id" : { "city" : "Pyote" }, "restaurants" : { "restaurants" : [ "Crave", "The Gala" ] } }

userProfileCity 값이 다른 값인 경우 이 작업은 다음 결과를 반환합니다.

{ "_id" : { "city" : "Bettles" }, "restaurants" : { "restaurants" : [ "Food Fury" ] } }
{ "_id" : { "city" : "Onida" }, "restaurants" : { "restaurants" : [ "The Wrap" ] } }
{ "_id" : { "city" : "Pyote" }, "restaurants" : { "restaurants" : [ "Crave" ] } }

init 함수는 maxrestaurants 필드를 포함하는 초기 상태를 정의합니다. max 필드는 해당 그룹의 최대 레스토랑 수를 설정합니다. 문서의 city 필드가 userProfileCity 와 일치하는 경우, 해당 그룹에는 최대 3 개의 레스토랑이 포함됩니다. 그렇지 않고 문서 _iduserProfileCity 와 일치하지 않으면 그룹에는 최대 1개의 레스토랑이 포함됩니다. init 함수는 initArgs 배열에서 city userProfileCity 인수를 모두 수신합니다.

$accumulator 가 처리하는 각 문서에 대해 레스토랑의 namerestaurants 배열로 푸시합니다(단, 해당 이름이 restaurants 의 길이를 max 값 위에 올리지 않는 경우). 문서가 처리될 때마다 축적 함수는 업데이트된 상태를 반환합니다.

병합 함수는 두 상태를 병합하는 방법을 정의합니다. 이 함수는 restaurant 각 상태의 배열을 함께 연결하고, 결과 배열의 길이는 slice() 메서드를 사용하여 max 값을 초과하지 않는지 확인합니다.

모든 문서가 처리되면 finalize 함수는 레스토랑 이름만 반환하도록 결과 상태를 수정합니다. 이 함수가 없으면 max 필드도 출력에 포함되어 애플리케이션에 대한 요구 사항을 충족하지 못합니다.

← abs (집계)

이 페이지의 내용