$accumulator (aggregation)
On this page本页内容
Definition定义
$accumulator
New in version 4.4.4.4版新增。Defines a custom accumulator operator.定义自定义累加器运算符。Accumulators are operators that maintain their state (e.g. totals, maximums, minimums, and related data) as documents progress through the pipeline.累加器是在文档通过管道时保持其状态(例如总数、最大值、最小值和相关数据)的运算符。Use the使用$accumulator
operator to execute your own JavaScript functions to implement behavior not supported by the MongoDB Query Language.$accumulator
运算符来执行您自己的JavaScript函数,以实现MongoDB查询语言不支持的行为。See also另请参见$function
.$function
。$accumulator
is available in these stages:可在以下阶段使用:ImportantExecuting JavaScript inside of an aggregation operator may decrease performance.在聚合运算符内部执行JavaScript可能会降低性能。Only use the如果提供的管道运算符不能满足应用程序的需要,则仅使用$accumulator
operator if the provided pipeline operators cannot fulfill your application's needs.$accumulator
运算符。
Syntax语法
The $accumulator
operator has this syntax:$accumulator
运算符的语法如下:
{
$accumulator: {
init: <code>,
initArgs: <array expression>, // Optional
accumulate: <code>,
accumulateArgs: <array expression>,
merge: <code>,
finalize: <code>, // Optional
lang: <string>
}
}
init | String or Code | init function receives its arguments from the initArgs array expression. initArgs 数组表达式接收其参数。init function has the following form: init 函数的形式如下:function (<initArg1>, <initArg2>, ...) { Note init() . init() 开始。init() , accumulate() , and merge() functions are compatible with this execution model. init() 、accumulate() 和merge() 函数与此执行模型兼容。 |
initArgs | Array | init function.init 函数的参数。initArgs [ <initArg1>, <initArg2>, ... ] Important $bucketAuto stage, initArgs cannot refer to the group key (i.e., you cannot use the $<fieldName> syntax). $bucketAuto 阶段中使用时,initArgs 不能引用组键(即,不能使用$<fieldName> 语法)。$bucketAuto stage, you can only specify constant values in initArgs . $bucketAuto 阶段中,您只能在initArgs 中指定常数值。 |
accumulate | String or Code | accumulate function receives its arguments from the current state and accumulateArgs array expression. accumulate 函数接收来自当前状态的参数和accumulateArgs 数组表达式。accumulate function becomes the new state. You can specify the function definition as either BSON type Code or String.accumulate 函数的结果成为新状态。可以将函数定义指定为BSON类型的“代码”或“字符串”。accumulate function has the following form: accumulate 函数具有以下形式:function(state, <accumArg1>, <accumArg2>, ...) { |
accumulateArgs | Array | accumulate function. accumulate 函数的参数。accumulateArgs to specify what field value(s) to pass to the accumulate function.accumulateArgs 指定要传递给accumulate 函数的字段值。accumulateArgs [ <accumArg1>, <accumArg2>, ... ] |
merge | String or Code | merge merge $merge .$merge 合并两个状态。merge function has the following form: merge 函数具有以下形式:function (<state1>, <state2>) { |
finalize | String or Code | finalize function has the following form: finalize 函数具有以下形式:function (state) { |
lang | String | $accumulator code. $accumulator 代码中使用的语言。Important lang is js . lang 唯一支持的值是js 。 |
Behavior行为
The following steps outline how the 以下步骤概述了$accumulator
operator processes documents:$accumulator
运算符如何处理文档:
The operator begins at an initial state, defined by the init function.运算符从初始状态开始,初始状态由init
函数定义。For each document, the operator updates the state based on the accumulate function.对于每个文档,运算符都会根据accumulate
函数更新状态。The accumulate function's first argument is the current state, and additional arguments are be specified in the accumulateArgs array.accumulate
函数的第一个参数是当前状态,另外的参数在accumulateArgs
数组中指定。When the operator needs to merge multiple intermediate states, it executes the merge function.当运算符需要合并多个中间状态时,它会执行merge
功能。For more information on when the merge function is called, see Merge Two States with有关何时调用$merge
.merge
函数的详细信息,请参阅使用$merge
合并两个状态。If a finalize function has been defined, once all documents have been processed and the state has been updated accordingly, finalize converts the state to a final output.如果定义了finalize
函数,则在处理完所有文档并相应更新了状态后,finalize
会将状态转换为最终输出。
Merge Two States with $merge
用$Merge
合并两种状态
$merge
As part of its internal operations, the 作为内部操作的一部分,$accumulator
operator may need to merge two separate, intermediate states. $accumulator
运算符可能需要合并两个独立的中间状态。The merge function specifies how the operator should merge two states.merge
函数指定运算符应如何合并两个状态。
For example, 例如,$accumulator
may need to combine two states when:$accumulator
可能需要在以下情况下组合两种状态:
$accumulator
is run on a sharded cluster.在分片集群上运行。The operator needs to merge the results from each shard to obtain the final result.运算符需要合并每个分片的结果以获得最终结果。A single单个$accumulator
operation exceeds its specified memory limit.$accumulator
操作超过了其指定的内存限制。If you specify the如果指定allowDiskUse
option, the operator stores the in-progress operation on disk and finishes the operation in memory.allowDiskUse
选项,则运算符会将正在进行的操作存储在磁盘上,并在内存中完成该操作。Once the operation finishes, the results from disk and memory are merged together using the merge function.操作完成后,将使用merge
函数将磁盘和内存的结果合并在一起。TipSee also:另请参阅:
Javascript Enabled启用
To use 要使用$accumulator
, you must have server-side scripting enabled.$accumulator
,必须启用服务器端脚本。
If you do not use 如果不使用$accumulator
(or $function
, $where
, or mapReduce
), disable server-side scripting:$accumulator
(或$function
、$where
或mapReduce
),请禁用服务器端脚本:
For a对于mongod
instance, seesecurity.javascriptEnabled
configuration option or--noscripting
command-line option.mongod
实例,请参阅security.javascriptEnabled
配置选项或--noscripting
命令行选项。For a对于mongos
instance, seesecurity.javascriptEnabled
configuration option or the--noscripting
command-line option starting in MongoDB 4.4.mongos
实例,请参阅从MongoDB 4.4开始的security.javascriptEnabled
配置选项或--noscripting
命令行选项。
In earlier versions, MongoDB does not allow JavaScript execution on在早期版本中,MongoDB不允许在mongos
instances.mongos
实例上执行JavaScript。
See also 另请参阅➤ Run MongoDB with Secure Configuration Options.使用安全配置选项运行MongoDB。
Unsupported Array and String Functions不支持的数组和字符串函数
MongoDB 6.0 upgrades the internal JavaScript engine used for server-side JavaScript, MongoDB 6.0升级了用于服务器端JavaScript、$accumulator
, $function
, and $where
expressions and from MozJS-60 to MozJS-91. Several deprecated, non-standard array and string functions that existed in MozJS-60 are removed in MozJS-91.$accumulator
、$function
和$where
表达式的内部JavaScript引擎,并从MozJS-60升级到MozJS-91。MozJS-60中存在的一些不推荐使用的非标准数组和字符串函数在MozJS-91中被删除。
For the complete list of removed array and string functions, see the 6.0 compatibility notes.有关已删除的数组和字符串函数的完整列表,请参阅6.0兼容性说明。
Examples实例
Use $accumulator
to Implement the $avg
Operator使用$accumulator
实现$avg
运算符
$accumulator
to Implement the $avg
OperatorThis example walks through using the 本例介绍如何使用$accumulator
operator to implement the $avg
operator, which is already supported by MongoDB. $accumulator
运算符来实现$avg
运算符,MongoDB已经支持该运算符。The goal of this example is not to implement new functionality, but to illustrate the behavior and syntax of the 这个例子的目的不是实现新的功能,而是用熟悉的逻辑来说明$accumulator
operator with familiar logic.$accumulator
运算符的行为和语法。
In 在mongosh
, create a sample collection named books
with the following documents: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 }
])
The following operation 以下操作按作者对文档进行分组,并使用groups
the documents by author
, and uses $accumulator
to compute the average number of copies across books for each author:$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"
}
}
}
}
])
Result结果
This operation returns the following result:此操作返回以下结果:
{ "_id" : "Dante", "avgCopies" : 1.6666666666666667 }
{ "_id" : "Homer", "avgCopies" : 10 }
Behavior行为
The $accumulator
defines an initial state where count
and sum
are both set to 0
. $accumulator
定义了一个初始状态,其中count
和sum
都设置为0
。For each document that the 对于$accumulator
processes, it updates the state by:$accumulator
处理的每个文档,它通过以下方式更新状态:
Incrementing the将count
by 1 andcount
增加1Adding the values of the document's将文档的copies
field to thesum
.copies
字段的值添加到sum
中。The accumulate function can access thecopies
field because it is passed in the accumulateArgs field.accumulate
函数可以访问copies
字段,因为它是在accumulateArgs
字段中传递的。
With each document that is processed, the accumulate function returns the updated state.对于处理的每个文档,accumulate
函数都会返回更新后的状态。
Once all documents have been processed, the finalize function divides the 处理完所有文件后,sum
of the copies by the count
of documents to obtain the average. finalize
函数将副本sum
除以文档count
,得到平均值。This removes the need to keep a running computed average, since the finalize function receives the cumulative 这消除了保持运行计算平均值的需要,因为sum
and count
of all documents.finalize
函数接收所有文档的累积sum
和count
。
Comparison with $avg
与$avg
的比较
$avg
This operation is equivalent to the following pipeline, which uses the 此操作等效于以下管道,该管道使用$avg
operator:$avg
运算符:
db.books.aggregate([
{
$group : {
_id : "$author",
avgCopies: { $avg: "$copies" }
}
}
])
Use initArgs
to Vary the Initial State by Group使用initArgs
按组更改初始状态
initArgs
to Vary the Initial State by GroupYou can use the initArgs option in to vary the initial state of 您可以在中使用$accumulator
. This can be useful if you want to, initArgs
选项来更改$accumulator
的初始状态。如果你想,这可能很有用,for example:例如:
Use the value of a field which is not in your state to affect your state, or使用不在您的状态中的字段的值来影响您的状态,或者Set the initial state to a different value based on the group being processed.根据正在处理的组将初始状态设置为不同的值。
In 在mongosh
, create a sample collection named restaurants
with the following documents: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" }
])
Suppose an application allows users to query this data to find restaurants. It may be useful to show more results for the city where the user lives. 假设一个应用程序允许用户查询这些数据来查找餐馆。显示用户所在城市的更多结果可能很有用。For this example, we assume that the user's city is called in a variable called 对于本例,我们假设在一个名为userProfileCity
.userProfileCity
的变量中调用用户的城市。
The following aggregation pipeline 以下聚合管道按groups
the documents by city
. city
对文档进行分组。The operation uses the 该操作使用$accumulator
to display a different number of results from each city depending on whether the restaurant's city matches the city in the user's profile:$accumulator
来显示每个城市的不同数量的结果,具体取决于餐厅的城市是否与用户配置文件中的城市匹配:
db.restaurants.aggregate([
{
$group :
{
_id : { city: "$city" },
restaurants:
{
$accumulator:
{
init: function(city, userProfileCity) { // Set the initial state
return {
max: city === userProfileCity ? 3 : 1, // If the group matches the user's city, return 3 restaurants
restaurants: [] // else, return 1 restaurant
}
},
initArgs: ["$city", <userProfileCity>], // Argument to pass to the init function
accumulate: function(state, restaurantName) { // Define how to update the state
if (state.restaurants.length < state.max) {
state.restaurants.push(restaurantName);
}
return state;
},
accumulateArgs: ["$name"], // Argument required by the accumulate function
merge: function(state1, state2) {
return {
max: state1.max,
restaurants: state1.restaurants.concat(state2.restaurants).slice(0, state1.max)
}
},
finalize: function(state) { // Adjust the state to only return field we need
return state.restaurants
}
lang: "js"
}
}
}
}
])
Results结果
If the value of 如果userProfileCity
is Bettles
, this operation returns the following result: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" ] } }
If the value of 如果userProfileCity
is Onida
, this operation returns the following result: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" ] } }
If the value of 如果userProfileCity
is Pyote
, this operation returns the following result:userProfileCity
的值为Pyote
,则此操作将返回以下结果:
{ "_id" : { "city" : "Bettles" }, "restaurants" : { "restaurants" : [ "Food Fury" ] } }
{ "_id" : { "city" : "Onida" }, "restaurants" : { "restaurants" : [ "The Wrap" ] } }
{ "_id" : { "city" : "Pyote" }, "restaurants" : { "restaurants" : [ "Crave", "The Gala" ] } }
If the value of 如果userProfileCity
is any other value, this operation returns the following result:userProfileCity
的值是任何其他值,则此操作将返回以下结果:
{ "_id" : { "city" : "Bettles" }, "restaurants" : { "restaurants" : [ "Food Fury" ] } }
{ "_id" : { "city" : "Onida" }, "restaurants" : { "restaurants" : [ "The Wrap" ] } }
{ "_id" : { "city" : "Pyote" }, "restaurants" : { "restaurants" : [ "Crave" ] } }
Behavior行为
The init function defines an initial state containing max
and restaurants
fields. init
函数定义了一个包含max
和restaurants
字段的初始状态。The max
field sets the maximum number of restaurants for that particular group. max
字段设置该特定组的最大餐厅数量。If the document's 如果文档的city
field matches userProfileCity
, that group contains a maximum of 3 restaurants. city
字段与userProfileCity
匹配,则该组最多包含3家餐厅。Otherwise, if the document 否则,如果文档的_id
does not match userProfileCity
, the group contains at most a single restaurant. _id
与userProfileCity
不匹配,则该组最多包含一个餐厅。The init function receives both the city
userProfileCity
arguments from the initArgs array.init
函数从initArgs
数组接收两个city
userProfileCity
参数。
For each document that the 对于initArgs处理的每个文档,它将餐厅的$accumulator
processes, it pushes the name
of the restaurant to the restaurants
array, provided that name would not put the length of restaurants
over the max
value. name
推送到restaurants
数组,前提是该名称不会使餐厅的长度超过最大值。With each document that is processed, the accumulate function returns the updated state.对于处理的每个文档,accumulate
函数都会返回更新后的状态。
The merge function defines how to merge two states. merge
函数定义如何合并两个状态。The function concatenates the 该函数将每个状态的restaurant
arrays from each state together, and the length of the resulting array is limited using the slice() method to ensure that it does not exceed the
max
value.restaurant
数组连接在一起,并使用slice()
方法限制结果数组的长度,以确保其不超过最大值。
Once all documents have been processed, the finalize function modifies the resulting state to only return the names of the restaurants. 处理完所有文档后,finalize
函数将修改结果状态,只返回餐厅的名称。Without this function, the 如果没有这个函数,max
field would also be included in the output, which does not fulfill any needs for the application.max
字段也将包含在输出中,这不能满足应用程序的任何需求。