I’m trying to optimize my code that I’m currently running on a node server.
The part of the code that I’m trying to optimize is code related with filtering something called "content" part of it’s schema is
const contentSchema = new Schema({
title: String ,
skills :[
{
skillId:ObjectId ,
skillLevel:Int
}]
})
I’m trying to filter it by the difficulty. each content’s difficulty is based on the skill with the highest level. so if the skill with the highest level is 5 then the content difficulty is 5.
How I’m currently doing it.
const content = await Content.find({
...someOtherFilters
}).lean()
content = content.map((content)=> {
const difficulty = content.skills.reduce((acc , curr)=> {
if (!acc || curr.skillLevel > acc) return curr.skillLevel
return acc
} , 0)
return {
...content,
difficulty
}
}).filter(({difficulty})=> {
return difficulty === desiredDifficulty
})
How can I convert this into some mongodb query that I can then use like this
const contentCount = await Cotnent.countDocuments(contentQuery)
3
Answers
Mapping and filtering can be done using
aggregate
.By using
$max
you can find which element in theskills
array has the highestskillLevel
and use$arrayElemAt
to pluck it from the array. You can then use$set
to set thedifficulty
to the value of thatskillLevel
.With this new
difficulty
property you can use$match
to find documents that match yourdesiredDifficulty
criteria.Something like this I think might help:
See HERE for a working example.
The answer by @jQuenny is correct and can be simplified to :
See how it works on the playground example
Instead of calculating the maximum difficulty on the fly, it would be best to store it as a property on the document, e.g.
maxDifficulty
. It should be updated whenever a new skill is added to the document. You will have very simple queries afterwards and you can support them by creating an index on the new property, e.g.:For updating existing documents, you can use an aggregation pipeline similar to the following (mongoplayground – thank you @jQueeny for the documents in your playground):
Please note that documents that do not contain any skills will not receive a
maxDifficulty
property. You can add an$ifNull
operator when setting the field to set themaxDifficulty
to 0 if needed.