Reputation: 107
I have a mongoose schema like this:
var schema = new Schema({
expenses: [{name: String, cost: number}]
});
schema.virtual('totalCost').get(function() {
let totalCost = 0;
this.expenses.forEach((expense)=> {
totalCost += expense.cost;
})
return totalCost;
})
Now I want to query all trips that have totalCost between minCost and maxCost. Is there any way I can do that? I tried $where but I can't pass minCost, maxCost to the function.
Upvotes: 1
Views: 591
Reputation: 2831
I think $where is the only way, you can achieve that but $where is costly.
I am not sure what are the options in mongoose to use $where but it would be something like below
var minCost=1000;
var maxCost = 10000;
query.$where(function () {
var cost=0;
for(var i in this.expenses){cost+=this.expenses[i].cost}
if(cost>minCost && cost<maxCost){return true;}
})
Here is the link
Another way is we can pass the javascript as a string in $where clause
var minCost=1000;
var maxCost = 10000;
var func = 'var cost=0;for(var i in this.expenses{cost+=this.expenses[i].cost}if(cost>'+minCost+' && cost<'+maxCost+'){return true;}'
query.$where(func);
Upvotes: 1
Reputation: 103365
You can't query against a Mongoose virtual property as they only exist in the Mongoose model representation of documents, not in MongoDB itself where the query should be executed against.
You can however run an aggregation query that calculates the total cost and then use the $match
pipeline to query the documents. The following example shows this approach:
Trip.aggregate([
{ "$unwind": "$expenses" },
{
"$group": {
"_id": "$_id",
"totalCost": { "$sum": "$expenses.cost" },
"expenses": { "$push": "$expenses" }
}
},
{
"$match": {
"totalCost": {
"$gte": minCost,
"$lte": maxCost
}
}
}
]).exec(callback);
Upvotes: 2