Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform text search together with geoNear?

I am programing a Mongo query builder and I found two statements in documentation:

(Text search) The $match stage that includes a $text must be the first stage in the pipeline.

(Geo search) You can only use $geoNear as the first stage of a pipeline.

Which basically means the same, so... how to use those together?

like image 808
PovilasID Avatar asked Mar 23 '14 19:03

PovilasID


1 Answers

I know this is an old question but I've recently had a similar problem so I thought I'd post my solution.

In my case I wanted:

  • first to use full-text search on user-supplied keywords as a filter
  • then, sort the results by distance from user-supplied coordinates
  • user could choose to provide keywords, location or both (the difficult case)

I tackled it with a block of code like this:


let query = {}

if(req.query.keywords){
  if(req.query.lng || req.query.lat){
    db.collection("service")
      .find({ $text: { $search: req.query.keywords }})
      .toArray()
      .then(docs => query._id = { $in: docs.map(doc => doc._id) })
  } else {
    query.$text = { $search: req.query.keywords }
  }
}

if(req.query.lat && req.query.lng){
  query.location = {
    $nearSphere: {
      $geometry: {
        type: "Point",
        coordinates: [req.query.lng, req.query.lat]
      }
    }
  }
}

db.collection("service").find(query)

Basically if a text search or a geo search is desired by itself, the appropriate query is built no problem. If both are needed, it does a text query first, and then passes the returned document ids as a filter to the second.

This is the most performant solution I could find!

like image 106
parasomnist Avatar answered Sep 28 '22 08:09

parasomnist