Is it possible to use variables defined in the $project
phase in that same phase?
For example, I have this aggregation pipeline:
pipeline = [
{ '$match': {} },
{
'$group': {
'_id': '$_id',
'n': { '$first': 'n' }
}
},
{
'$project': {
'name': 1,
'n': 1,
'revenue': { '$multiply': ['$n', 2] },
'cost': { '$multiply': ['$revenue', 0.25] }
}
}
]
I'd like to use the $revenue
variable (that I defined in $project
) in the same $project
stage to compute the value of cost
, but this does not work.
Is there any way I can do this easily and efficiently? I thought about doing several projections but I would need to project many variables (~25 variables) every time I need to compute one additional variable, and I have a bunch of variables to compute that are depending on each other (~5 variables), and my code would probably look bad since there would be a lot of projecting of the same variables. How should I go about this?
No, but you can nest projection operators as a work-around:
pipeline = [{
'$match': {}
},
{
'$group': {
'_id': '$_id',
'n': {'$first': 'n'}
},
{
'$project': {
'name': 1,
'n': 1,
'revenue': {'$multiply': ['$n', 2]},
'cost': {'$multiply': [{'$multiply': ['$n', 2]}, 0.25]}
}
}]
Which in this case you could simplify to:
pipeline = [{
'$match': {}
},
{
'$group': {
'_id': '$_id',
'n': {'$first': 'n'}
},
{
'$project': {
'name': 1,
'n': 1,
'revenue': {'$multiply': ['$n', 2]},
'cost': {'$multiply': ['$n', 2, 0.25]}
}
}]
Just landed here while searching for the same issue. My current solution is adding more $project stages and always take all other fields. For your example it would look like this:
pipeline = [{
'$match': {}
},
{
'$group': {
'_id': '$_id',
'n': {'$first': 'n'}
},
{
'$project': {
'name': 1,
'n': 1,
'revenue': {'$multiply': ['$n', 2]}
}
},
{
'$project': {
'name': 1,
'n': 1,
'revenue': 1,
'cost': {'$multiply': ['$revenue', 0.25]}
}
}]
I did not find any better solution yet if you want to keep all previous computed fields, without reusing expressions several times.
Starting in Mongo 3.4
, you can use a series of $addFields
stages rather than verbose $project
stages.
This way, you can keep on projecting additional fields, some of which can re-use fields previously computed:
// { name: "a", n: 3 }
// { name: "b", n: 5 }
db.collection.aggregate([
{ $addFields: { revenue: { $multiply: ["$n", 2] } } },
{ $addFields: { cost: { $multiply: ["$revenue", 0.25] } } } // re-use "revenue"
])
// { name: "a", n: 3, revenue: 6, cost: 1.5 }
// { name: "b", n: 5, revenue: 10, cost: 2.5 }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With