First of all, no matter which solution you use, you must make the $match stage for your filter first. Otherwise you are doing massive unnecessary analysis of documents that won’t match any part of your filter.
Having said that, you have now added two sort criteria, first sort by documents matching the most $or
clauses, but then you added that if the $or clause is $in
then you want sort based on how many items inside $in
were matched…
Combining all the suggestions with proper filtering, you would do something like this:
let filter1 = { array1: { $in: [1, 2, 3, 4, 5] } };
let filter2 = { array2: { $in: [6, 7, 8, 9, 10] } };
let filter3 = { array3: {$in: ["a", "b", "c"]} };
let query = { $or: [filter1, filter2, filter3] }
[
{$match: query},
{$set:{sortScore:{$sum:[
{$size:{$setIntersection:[ {$ifNull:["$array1",[]]}, [1, 2, 3, 4, 5]]}},
{$size:{$setIntersection:[ {$ifNull:["$array2",[]]}, [6, 7, 8, 9, 10]]}},
{$size:{$setIntersection:[ {$ifNull:["$array3",[]]}, ["a", "b", "c"]]}}
]}}},
{$sort:{ sortScore: -1 }}
]
I corrected a few other minor errors - you want to sort descending to get highest matches first, etc.
You can also add {$project:{sortScore:0}}
at the end to remove the score you sorted by.
By the way, are the $or
clauses always $in
with scalar values? Or do you need a more generalized solution? This one will only work assuming they are always arrays and filters are $in
clauses.
Asya