user1740626
user1740626

Reputation: 53

Mongo get results in order of maximum matches of value

I've a Document like this:

{
   {
      name: 'The best book'
   },

   {
      name: 'The book is the best on Sachin'
   },

   {
      name: 'Best book on Sachin Tendulkar'
   }

}

I've search regex mongo query:

db.getCollection('books').find({ $in: [/sachin/i, /tendulkar/i, /best/i, /book/i]})

It's giving results, but as per my requirement it should give results in sorted order of maximum matches:

{
    name: 'Best book on Sachin Tendulkar'      (4 matches)
},
{
    name: 'The book is the best on Sachin'     (3 matches)  
},
{
    name: 'The best book'                       (2 matches)
}

I'm new to mongo. Please help me in writing the mongo query for getting the results.

Upvotes: 0

Views: 710

Answers (1)

martskins
martskins

Reputation: 2940

Your best bet may be to use the aggregation framework (https://docs.mongodb.com/v3.2/reference/operator/aggregation/) in this case. I'd do it like this.

  1. Split text into an array of words
  2. Intersect the array of tags you want to match with the array produced in step 1.
  3. Project the size of the intersection into a field
  4. Sort by the field projected in step 3.

Something along these lines

db.books.aggregate([
    {$match: {}},
    {$project: {
        name: {$toLower: "$name"},
        ... any other amount of fields ...
    }},
    {$project: {
        name: true,
        ... any other amount of fields ...
        wordArray: {$split: ["$name", " "]}
    }},
    {$project: {
        name: true,
        ... any other amount of fields ...
        wordArray: true,
        numberOfMatches: {
            $size: {
                $setIntersection: ["$wordArray", ["best", "book"]]
            }
        }
    }},
    {$sort: {
        numberOfMatches: -1
    }}
]);

Keep in mind that you can put a condition where $match: {} is, and filter the initial set of books you're classifying.

I'm not sure if this works with regular expressions though, so I added the first $project phase as a way to ensure you're always comparing lowercase to lowercase

Upvotes: 1

Related Questions