Definition定义
$accumulator-
Important
Server-side JavaScript Deprecated服务器端JavaScript已弃用Starting in MongoDB 8.0, server-side JavaScript functions (从MongoDB 8.0开始,服务器端JavaScript函数($accumulator,$function,$where) are deprecated. MongoDB logs a warning when you run these functions.$accumulator、$function、$where)被弃用。当您运行这些函数时,MongoDB会记录一个警告。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使用$accumulatoroperator to execute your own JavaScript functions to implement behavior not supported by the MongoDB Query Language. See also$function.$accumulator运算符执行您自己的JavaScript函数,以实现MongoDB查询语言不支持的行为。另请参见$function。$accumulatoris available in these stages:在以下阶段可用:Important
Executing JavaScript inside of an aggregation operator may decrease performance. Only use the在聚合运算符中执行JavaScript可能会降低性能。仅当提供的管道运算符无法满足应用程序的需求时,才使用$accumulatoroperator if the provided pipeline operators cannot fulfill your application's needs.$accumulator运算符。
Syntax语法
The $累加器运算符具有以下语法:$accumulator operator has this syntax:
{
$accumulator: {
init: <code>,
initArgs: <array expression>, // Optional
accumulate: <code>,
accumulateArgs: <array expression>,
merge: <code>,
finalize: <code>, // Optional
lang: <string>
}
}
init | String or Code |
|
initArgs |
| |
accumulate | String or Code |
|
accumulateArgs |
| |
merge | String or Code |
|
finalize | String or Code |
|
lang |
|
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. 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合并两个状态
$mergeAs 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函数指定运算符应如何合并两个状态。
The merge function always merges two states at a time. In the event that more than two states must be merged, the resulting merge of two states is merged with a single state. This process repeats until all states are merged.merge函数总是一次合并两个状态。如果必须合并两个以上的状态,则两个状态的合并结果将与单个状态合并。重复此过程,直到合并所有状态。
For example, 例如,在以下情况下,$accumulator may need to combine two states in the following scenarios:$accumulator可能需要组合两个状态:
$accumulatoris run on a sharded cluster. The operator needs to merge the results from each shard to obtain the final result.在分片集群上运行。运算符需要合并每个分片的结果以获得最终结果。A single单个$accumulatoroperation exceeds its specified memory limit. If you specify theallowDiskUseoption, the operator stores the in-progress operation on disk and finishes the operation in memory.$accumulator操作超过了其指定的内存限制。如果指定allowDiskUse选项,运算符会将正在进行的操作存储在磁盘上,并在内存中完成操作。Once the operation finishes, the results from disk and memory are merged together using the merge function.操作完成后,使用merge函数将磁盘和内存的结果合并在一起。
Document Processing Order文档处理顺序
The order that MongoDB processes documents for the MongoDB为init(), accumulate(), and merge() functions can vary, and might differ from the order that those documents are specified to the $accumulator function.init()、accumulate()和merge()函数处理文档的顺序可能会有所不同,并且可能与这些文档指定给$accumulator函数的顺序不同。
For example, consider a series of documents where the 例如,考虑一系列文档,其中_id fields are the letters of the alphabet:_id字段是字母表中的字母:
{ _id: 'a' },
{ _id: 'b' },
{ _id: 'c' }
...
{ _id: 'z' }
Next, consider an aggregation pipeline that sorts the documents by the 接下来,考虑一个聚合管道,它按_id field and then uses an $accumulator function to concatenate the _id field values:_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 does not guarantee that the documents are processed in the sorted order, meaning the MongoDB不保证文档按排序顺序处理,这意味着alphabet field does not necessarily get set to abc...z.alphabet字段不一定设置为abc...z。
Due to this behavior, ensure that your 由于这种行为,请确保$accumulator function does not need to process and return documents in a specific order.$accumulator函数不需要按特定顺序处理和返回文档。
Javascript EnabledJavascript已启用
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对于mongodinstance, seesecurity.javascriptEnabledconfiguration option or--noscriptingcommand-line option.mongod实例,请参阅security.javascriptEnabled配置选项或--noscripting命令行选项。For a对于mongosinstance, seesecurity.javascriptEnabledconfiguration option or the--noscriptingcommand-line option.mongos实例,请参阅security.javascriptEnabled配置选项或--noscripting命令行选项。In earlier versions, MongoDB does not allow JavaScript execution on在早期版本中,MongoDB不允许在mongosinstances.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. $accumulator、$function和$where表达式的内部JavaScript引擎从MozJS-60升级到MozJS-91。Several deprecated, non-standard array and string functions that existed in MozJS-60 are removed in MozJS-91.MozJS-60中存在的几个已弃用的非标准数组和字符串函数在MozJS-91中被删除。
Examples示例
Use $accumulator to Implement the $avg Operator使用$accumulator实现$avg运算符
$accumulator to Implement the $avg OperatorNote
This 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: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. For each document that the $accumulator processes, it updates the state by:$accumulator定义了一个初始状态,其中count和sum都设置为0。对于$accumulator处理的每个文档,它通过以下方式更新状态:
Incrementing the将countby 1 andcount递增1Adding the values of the document's将文档copiesfield to thesum.copies字段的值添加到sum中。The accumulate function can access thecopiesfield 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的比较
$avgThis 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, for example:initArgs选项来改变$accumulator的初始状态。如果你愿意,这可能很有用,例如:
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显示来自每个城市的不同数量的结果,具体取决于餐厅的城市是否与用户个人资料中的城市匹配:
Note
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如果该组与用户所在城市匹配,则返回3家餐厅
restaurants: [] // else, return 1 restaurant否则,返回1家餐厅
}
},
initArgs: ["$city", <userProfileCity>], // Argument to pass to the init function传递给init函数的参数
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. document_id与userProfileCity不匹配,则该组最多包含一家餐厅。The init function receives both the city userProfileCity arguments from the initArgs array.init函数从initArgs数组接收city userProfileCity参数。
For each document that the 对于$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. With each document that is processed, the accumulate function returns the updated state.$accumulator处理的每个文档,它将餐厅的name推送到restaurants数组中,前提是名称不会使restaurants的长度超过max值。对于处理的每个文档,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字段也将包含在输出中,这无法满足应用程序的任何需求。