The custom aggregate expression operator mainly completes more complex aggregate query operations by customizing some Javascript functions; in this article, we mainly introduce the use of $accumulator :
1. Preparation
Initialize course grade data
db.subjectScores.insertMany([
{ "_id": 1, "name": "张三", "subject": "eng", "score": 80 },
{ "_id": 2, "name": "李四", "subject": "eng", "score": 60 },
{ "_id": 3, "name": "王五", "subject": "eng", "score": 90 },
{ "_id": 4, "name": "张三", "subject": "math", "score": 70 },
{ "_id": 5, "name": "李四", "subject": "math", "score": 90 },
{ "_id": 6, "name": "王五", "subject": "math", "score": 50 },
{ "_id": 7, "name": "张三", "subject": "physics", "score": 80 },
{ "_id": 8, "name": "李四", "subject": "physics", "score": 60 },
{ "_id": 9, "name": "王五", "subject": "physics", "score": 70 }
])
Two, $accumulator
grammar:
{
$accumulator: {
init: <code>,
initArgs: <array expression>, // Optional
accumulate: <code>,
accumulateArgs: <array expression>,
merge: <code>,
finalize: <code>, // Optional
lang: <string>
}
}
init: The function is used to initialize the state object and receive parameters from initArgs
function (<initArg1>, <initArg2>, ...) {
...
return <initialState>
}
initArgs: optional, list of initialization parameters
[ <initArg1>, <initArg2>, ... ]
accumulate: The function is used to accumulate documents, the first parameter is the state object, other parameters are received from accumulateArgs; returns a new state object
function(state, <accumArg1>, <accumArg2>, ...) {
...
return <newState>
}
accumulateArgs: list of accumulated arguments
[ <accumArg1>, <accumArg2>, ... ]
merge: The function is used to merge two state objects; returns a new state object
function (<state1>, <state2>) {
<logic to merge state1 and state2>
return <newState>
}
finalize: The function is used to return the aggregation result
function (state) {
...
return <finalState>
}
lang: the language used, currently only supports js
$accumulator can only be used in 4.4 and later versions
3. Example: Calculate the total score of the students
Aggregation queries are as follows:
db.subjectScores.aggregate([
{
$group: {
"_id": "$name",
"score": {
$accumulator: {
init: function() {
return {
sum: 0
}
},
accumulate: function(state, score) {
return {
sum: state.sum + score
}
},
accumulateArgs: [ "$score" ],
merge: function(state1, state2) {
return {
sum: state1.sum + state2.sum
}
},
finalize: function(state) {
return state.sum
},
lang: "js"
}
}
}
}
])
We explain the aggregation query above:
1. Group course grade documents by name
2. Initialize the state object and accumulate and sum the scores in the input documents
3. Merge state objects
4. Return the sum value in the state object as the total score
The aggregation query above is equivalent to:
db.subjectScores.aggregate([
{
$group: {
"_id": "$name",
"score": { $sum: "$score" }
}
}
])
The results of the aggregation query are as follows:
{ "_id" : "王五", "score" : 210 }
{ "_id" : "李四", "score" : 210 }
{ "_id" : "张三", "score" : 230 }