The question is the next one:
Get documents with tags in list, ordered by total number of matches
But they say that is possible using Aggregation Framework, it's possible?
The question is the next one:
Get documents with tags in list, ordered by total number of matches
But they say that is possible using Aggregation Framework, it's possible?
Yes, it's possible using Aggregation Framework.
Assumptions
tags
attribute is a set (no repeated elements)Query
This approach forces you to unwind the results and reevaluate the match predicate with unwinded results, so its really inefficient.
db.test_col.aggregate(
{$match: {tags: {$in: ["shirt","cotton","black"]}}},
{$unwind: "$tags"},
{$match: {tags: {$in: ["shirt","cotton","black"]}}},
{$group: {
_id:{"_id":1},
matches:{$sum:1}
}},
{$sort:{matches:-1}}
);
Expected Results
{
"result" : [
{
"_id" : {
"_id" : ObjectId("5051f1786a64bd2c54918b26")
},
"matches" : 3
},
{
"_id" : {
"_id" : ObjectId("5051f1726a64bd2c54918b24")
},
"matches" : 2
},
{
"_id" : {
"_id" : ObjectId("5051f1756a64bd2c54918b25")
},
"matches" : 1
}
],
"ok" : 1
}
Using $size and $setIntersection will solve this efficiently, without causing memory multiplication.
tagList = ['shirt', 'cotton', 'black']
db.test_col.aggregate(
{$match: {tags: {$in: ["shirt","cotton","black"]}}},
{$project:
{"title":1,"tags":1},
{$order:
{"$size":
{"$setIntersection": [ tagList, "$tags" ]}},
{$sort:{order:-1}}
);
First we match the documents which have at least one element matching.
Then we project Keys/Columns we need along with a new order key/column. Order is generated by taking the count of intersected elements between 'tags in db' and 'tags from query'.
Then we do a simple sort in descending order. This worked for me. Similar Question answered here