$function (aggregation) (original) (raw)
$function
Important
Server-side JavaScript Deprecated
Starting in MongoDB 8.0, server-side JavaScript functions ($accumulator, $function, $where) are deprecated. MongoDB logs a warning when you run these functions.
Defines a custom aggregation function or expression in JavaScript.
You can use the $function operator to define custom functions to implement behavior not supported by the MongoDB Query Language. See also $accumulator.
Important
Executing JavaScript inside an aggregation expression may decrease performance. Only use the $functionoperator if the provided pipeline operators cannot fulfill your application's needs.
The $function operator has the following syntax:
{
$function: {
body: <code>,
args: <array expression>,
lang: "js"
}
}
Field | Type | Description |
---|---|---|
body | String or Code | The function definition. You can specify the function definition as either BSON type Code or String. See alsolang.function(arg1, arg2, ...) { ... }or"function(arg1, arg2, ...) { ... }" |
args | Array | Arguments passed to the function body. If the body function does not take an argument, you can specify an empty array [ ].The array elements can be any BSON type, including Code. SeeExample 2: Alternative to $where. |
lang | String | The language used in the body. You must specify lang: "js". |
You cannot use $function as part of a schema validation query predicate.
To use $function, you must have server-side scripting enabled (default).
If you do not use $function (or $accumulator,$where, or mapReduce), disable server-side scripting:
- For a mongod instance, seesecurity.javascriptEnabled configuration option or--noscripting command-line option.
- For a mongos instance, seesecurity.javascriptEnabled configuration option or the--noscripting command-line option.
In earlier versions, MongoDB does not allow JavaScript execution onmongos instances.
See also ➤ Run MongoDB with Secure Configuration Options.
The query operator $where can also be used to specify JavaScript expression. However:
- The $expr operator allows the use ofaggregation expressions within the query language.
- The $function and $accumulator allows users to define custom aggregation expressions in JavaScript if the provided pipeline operators cannot fulfill your application's needs.
Given the available aggregation operators:
- The use of $expr with aggregation operators that do not use JavaScript (i.e. non-$function and non-$accumulator operators) is faster than $wherebecause it does not execute JavaScript and should be preferred if possible.
- However, if you must create custom expressions,$function is preferred over $where.
MongoDB 6.0 upgrades the internal JavaScript engine used forserver-side JavaScript,$accumulator, $function, and $whereexpressions 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.
For the complete list of removed array and string functions, see the6.0 compatibility notes.
Create a sample collection named players
with the following documents:
db.players.insertMany([
{ _id: 1, name: "Miss Cheevous", scores: [ 10, 5, 10 ] },
{ _id: 2, name: "Miss Ann Thrope", scores: [ 10, 10, 10 ] },
{ _id: 3, name: "Mrs. Eppie Delta ", scores: [ 9, 8, 8 ] }
])
The following aggregation operation uses $addFields to add new fields to each document:
isFound
whose value is determined by the custom$function expression that checks whether the MD5 hash of the name is equal to a specified hash.message
whose value is determined by the custom$function expression that format a string message using a template.
db.players.aggregate( [
{ $addFields:
{
isFound:
{ $function:
{
body: function(name) {
return hex_md5(name) == "15b0a220baa16331e8d80e15367677ad"
},
args: [ "$name" ],
lang: "js"
}
},
message:
{ $function:
{
body: function(name, scores) {
let total = Array.sum(scores);
return `Hello <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>n</mi><mi>a</mi><mi>m</mi><mi>e</mi></mrow><mi mathvariant="normal">.</mi><mi>Y</mi><mi>o</mi><mi>u</mi><mi>r</mi><mi>t</mi><mi>o</mi><mi>t</mi><mi>a</mi><mi>l</mi><mi>s</mi><mi>c</mi><mi>o</mi><mi>r</mi><mi>e</mi><mi>i</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">{name}. Your total score is </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">nam</span><span class="mord mathnormal">e</span></span><span class="mord">.</span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mord mathnormal">o</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mord mathnormal">t</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">score</span><span class="mord mathnormal">i</span><span class="mord mathnormal">s</span></span></span></span>{total}.`
},
args: [ "$name", "$scores"],
lang: "js"
}
}
}
}
] )
The operation returns the following documents:
{ "_id" : 1, "name" : "Miss Cheevous", "scores" : [ 10, 5, 10 ], "isFound" : false, "message" : "Hello Miss Cheevous. Your total score is 25." }
{ "_id" : 2, "name" : "Miss Ann Thrope", "scores" : [ 10, 10, 10 ], "isFound" : true, "message" : "Hello Miss Ann Thrope. Your total score is 30." }
{ "_id" : 3, "name" : "Mrs. Eppie Delta ", "scores" : [ 9, 8, 8 ], "isFound" : false, "message" : "Hello Mrs. Eppie Delta . Your total score is 25." }
Note
Aggregation Alternatives Preferred over $where
The $expr operator allows the use ofaggregation expressions within the query language. And the $function and $accumulatorallows users to define custom aggregation expressions in JavaScript if the provided pipeline operators cannot fulfill your application's needs.
Given the available aggregation operators:
- The use of $expr with aggregation operators that do not use JavaScript (i.e. non-$function and non-$accumulator operators) is faster than$where because it does not execute JavaScript and should be preferred if possible.
- However, if you must create custom expressions,$function is preferred over $where.
As an alternative to a query that uses the $where operator, you can use $expr and $function. For example, consider the following $where example.
db.players.find( { $where: function() {
return (hex_md5(this.name) == "15b0a220baa16331e8d80e15367677ad")
} } );
The db.collection.find() operation returns the following document:
{ "_id" : 2, "name" : "Miss Ann Thrope", "scores" : [ 10, 10, 10 ] }
The example can be expressed using $expr and $function:
db.players.find( {$expr: { $function: {
body: function(name) { return hex_md5(name) == "15b0a220baa16331e8d80e15367677ad"; },
args: [ "$name" ],
lang: "js"
} } } )