1
votes

I have a REST API Call like /item/search which has some query parameters attached to it.

The user can search for entire term or just 3 or more characters of a term.

The Node.JS exports function is as follows,

exports.getSearchedItems = function(req,res){
var searchText = req.query.q;
var searchedString = searchText.replace(/ /g,"|");

var nameRegex = new RegExp('\\b' + searchedString + '.*', 'i');

Item.find()
    .or([
         {$text: {$search: searchText } },
         {'name': {$regex: nameRegex } },
         {'score':{'$meta': 'textScore'}
        ]
       )
    .sort({'score':{'$meta': 'textScore'}}
    .exec(function(err, items){
         if(err) console.log('Error Finding Query ' +err);
            res.send(items);
         });
};

A query Like item/search?q=new+2,

We get the below Error,

Can't canonicalize query: BadValue must have $meta projection for all $meta sort keys

Is there any way I can do a partial OR full search yet maintain the textScore and sort my resulting mongoose documents as per that score.

Cheers and Thanks in Advance.

1

1 Answers

3
votes

MongoDB's find() method can take a second optional argument indicating which fields to return and in your case of $text search, the special projection field $meta allows you to get back the score of the matched document so that you can sort on it.

Try modifying your find() query to include the query and the $meta projection as the find() arguments instead of the or() method:

Item.find(
    { 
        "$or":[ {"$text": {"$search": searchText } }, {"name": {"$regex": nameRegex } } ]
    }, 
    { 
        "score" : { "$meta" : "textScore"} 
    })
  .sort({"score": { "$meta": "textScore"} })
  .exec(function(err, items){
      if(err) console.log("Error Finding Query " + err);
      res.send(items);
  });