Sorry for the title I don't know how to express the problem better.
I'm trying to sum the total spent money on book items in the MongoDB document. That means before calculating the array must be filtered that only bought books are considered when calculating the total spent money.
This is an example document (I removed some fields so it doesn't get too big):
{
"_id" : ObjectId("598cb3f4ca693a0688004e2a"),
"title" : {
"de" : "Another",
"ja" : "アナザー",
"roomaji" : "Another"
},
"total" : 4,
"volumes" : [
{
"volume" : 1,
"edition" : 1,
"price" : 7,
"releaseDate" : 1342051200,
"bought" : true,
"read" : true
},
{
"volume" : 2,
"edition" : 1,
"price" : 7,
"releaseDate" : 1347494400,
"bought" : true,
"read" : true
},
{
"volume" : 3,
"edition" : 1,
"price" : 7,
"releaseDate" : 1352419200,
"bought" : false,
"read" : false
},
{
"volume" : 4,
"edition" : 1,
"price" : 7,
"releaseDate" : 1357776000,
"bought" : false,
"read" : false
}
],
"releaseYear" : 2012
}
So, I want to sum the price field of all volume objects, but only those where "bought" is set to true. As result I would like to get this output:
{
"_id" : ObjectId(),
"title" : {
'de' : 'title'
},
"count" : 14
}
And this is my PHP-Code
$result = $mongo->Book->aggregate([
[
'$group' => [
'_id' => '$_id',
'title' => ['$push' => '$title.de'],
'count' => [
'$sum' => [
'$map' => [
'input' => '$volumes',
'as' => 'vol',
'in' => [
'$cond' => [
[
'$eq' => ['$$vol.bought', true]
],
'$$vol.price',
0
]
]
],
]
]
]
],
[
'$sort' => [
'count' => -1
]
]
]);
But count always returns 0. What I'm doing wrong?
It's always returning 0 because the $sum
operator in the $group
pipeline step expects an expression which evaluates to a numerical value yet here the supplied $map
expression evaluates to an array. Also the in
value of the $map
operator is an expression that is applied to each element of the input array which references each element individually with the variable name specified in as
hence no filtering is involved as the $cond
operator is redundant here.
You need to filter the array first using $filter
then you can map the elements. Fortunately for your case the $sum
operator can be used in the $project
stage as it returns the sum of the specified list of expressions for each document.
Consider running the following pipeline to get the desired result:
$result = $mongo->Book->aggregate([
[
"$project" => [
"title.de" => "$title.de",
"count" => [
"$sum" => [
"$map" => [
"input" => [
"$filter" => [
"input" => "$volumes",
"as" => "vol",
"cond" => "$$vol.bought"
]
],
"as" => "el",
"in" => "$$el.price"
]
]
]
]
],
[
'$sort' => [
'count' => -1
]
]
])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.