On this page本页内容
$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:在以下阶段可用:
Executing 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运算符。
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 |
function (<initArg1>, <initArg2>, ...) { ... return <initialState> } |
initArgs | Array |
[ <initArg1>, <initArg2>, ... ]
|
accumulate | String or Code |
function(state, <accumArg1>, <accumArg2>, ...) { ... return <newState> } |
accumulateArgs | Array |
[ <accumArg1>, <accumArg2>, ... ] |
merge | String or Code |
function (<state1>, <state2>) { <logic to merge state1 and state2> return <newState> } |
finalize | String or Code |
function (state) { ... return <finalState> } |
lang | String |
|
The following steps outline how the 以下步骤概述了$accumulator operator processes documents:$accumulator运算符如何处理文档:
init函数定义。accumulate函数更新状态。accumulate函数的第一个参数是当前状态,可以在accumulateArgs数组中指定其他参数。merge函数。$merge.merge函数的详细信息,请参阅使用$merge合并两个状态。finalize函数,则在处理完所有文档并相应更新状态后,finalize将状态转换为最终输出。$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可能需要在以下情况下组合两种状态:
$accumulatorA 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函数将磁盘和内存的结果合并在一起。
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),请禁用服务器端脚本:
mongod instance, see security.javascriptEnabled configuration option or --noscripting command-line option.mongod实例,请参阅security.javascriptEnabled配置选项或--noscripting命令行选项。For a mongos instance, see security.javascriptEnabled configuration option or the --noscripting command-line option starting in MongoDB 4.4.
mongos instances.mongos实例上执行JavaScript。See also ➤ Run MongoDB with Secure Configuration Options.请参阅➤ 使用安全配置选项运行MongoDB。
$accumulator to Implement the $avg Operator$accumulator实现$avg运算符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"
}
}
}
}
])
This operation returns the following result:此操作返回以下结果:
{ "_id" : "Dante", "avgCopies" : 1.6666666666666667 }
{ "_id" : "Homer", "avgCopies" : 10 }
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处理的每个文档,它通过以下方式更新状态:
count by 1 andcount递增1,并且copies field to the sum. copies字段的值添加到sum。copies field because it is passed in the accumulateArgs field.copies字段,因为它是在accumulateArgs字段中传递的。With each document that is processed, the accumulate function returns the updated state.对于处理的每个文档,累积函数返回更新的状态。
Once all documents have been processed, the finalize function divides the 处理完所有文档后,finalize函数将副本sum of the copies by the count of documents to obtain the average. sum除以文档count,以获得平均值。This removes the need to keep a running computed average, since the finalize function receives the cumulative 这消除了保持运行计算平均值的需要,因为finalize函数接收所有文档的sum and count of all documents.sum和和count。
$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" }
}
}
])
initArgs to Vary the Initial State by GroupinitArgs按组更改初始状态You can use the initArgs option in to vary the initial state of 您可以使用中的$accumulator. initArgs选项更改$accumulator的初始状态。This can be useful if you want to, for example:例如,如果您希望:
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"
}
}
}
}
])
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" ] } }
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 对于$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. $accumulator处理的每个文档,它将餐馆的name推送到restaurants数组,前提是该名称不会使restaurants的长度超过max值。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字段也将包含在输出中,这不能满足应用程序的任何需求。