In my meteor app, I have a huge collection of documents, each with a field tags
, basically like this:
{..., tags: ["a","b","c"], ...},
{..., tags: ["a","b","d"], ...},
{..., tags: ["b","c","e"], ...},
{..., tags: ["x","y","z"], ...},
....
Now i want to query the collection on the server with some tags, eg: ["a","d","y"]
and get all results that match at least one tag, and the resultset sorted by the number of matching tags. So, in the exampleset the result should be:
{..., tags: ["a","b","d"], ...},
{..., tags: ["a","b","c"], ...},
{..., tags: ["x","y","z"], ...}
because the first doc has two matches, "a"
and "d"
, and the other two elements have one match, "a"
and "y"
.
Currently I know that I can use $in
to match all documents that have at least one match, $all
to get all documents where every tag matches, but this doesn't cut it somehow. I could also use mongoDB's aggregate framework if needed.
What would the needed query look like?
MongoDB query to find matching documents given an array with values? For specific documents, use MongoDB $ in. Let us create a collection with documents − Display all documents from a collection with the help of find () method −
Find method is used to fetch a document from the MongoDB collection. Using the Find method, we can fetch specific documents as well as the particular fields that we need. We can also use other find methods to retrieve specific documents as per our requirement.
There are totally six methods available in Mongo DB by which we can fetch particular records. Find method consists of two parameters by which we can fetch a particular record. If we don’t use these two parameters then the find method will return all the documents available within the MongoDB collection.
If we don’t use these two parameters then the find method will return all the documents available within the MongoDB collection. Query – This is an optional parameter which defines the selection criteria.
I could also use mongoDB's aggregate framework if needed.
You need to use the the aggregation pipeline, which can be written as below:
Match
the documents having at least one matching value in the tags
array.Unwind
the tags
array.Match
the records which have their tags value present in the input array.Group
by the _id
field and calculate the number of documents that have matched.Sort
the groups based on their number of matches.project
the required fields along with the original tags array copy we had created. Code:
var inp = ["a","d","y"];
db.collection.aggregate([
{$match:{"tags":{$in:inp}}},
{$project:{"tagsCopy":"$tags","tags":1}},
{$unwind:"$tags"},
{$match:{tags:{$in:inp}}},
{$group:{"_id":"$_id","noOfMatches":{$sum:1},"tags":{$first:"$tagsCopy"}}},
{$sort:{noOfMatches:-1}},
{$project:{"_id":0,"noOfMatches":1,tags:1}} //remove noOfMatches and
//add other required
//fields which are necessary.
])
o/p:
{ "noOfMatches" : 2, "tags" : [ "a", "b", "d" ] }
{ "noOfMatches" : 1, "tags" : [ "x", "y", "z" ] }
{ "noOfMatches" : 1, "tags" : [ "a", "b", "c" ] }
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