nicholaides nicholaides - 4 months ago 23
Ruby Question

Mongo full text search with score via Ruby driver

In the Mongo documentation, it says you can do this:

db.articles.find(
{ $text: { $search: "cake" } },
{ score: { $meta: "textScore" } }
)


That works fine when I run it from the mongo console but I can't figure out how to do that via the Ruby driver.

When I do this:

articles.find('$text': { '$search': 'cake' }, score: { '$meta': 'textScore' })


I get

Mongo::Error::OperationFailure: unknown operator: $meta (2)


When I do

articles.find({ '$text': { '$search': 'cake' } }, score: { '$meta': 'textScore' })


I get results but it doesn't include the score and the log message doesn't show that it's using the
score: { $meta': 'textScore' }
:

{"find"=>"articles", "filter"=>{"$text"=>{"$search"=>"cake"}}}


I guess I just don't grok how the Ruby driver and Mongo CLI convert those into Mongo queries.

I'm using MongoDB version v3.2.7 and the mongo gem version 2.2.5.

Answer

Let's look to structure of mongo command:

db.collection.find(
   <query>,
   { score: { $meta: "textScore" } }
)

We see that command contains two parts (in this case find)

  1. <query>
  2. options hash

Structure of command in mongo-driver very similar to mongo. But some things are not simple.

In mongo-driver we have Mongo::Collection::View, check (link to source):

articles.find({ '$text': { '$search': 'cake' } }.class # => Mongo::Collection::View

So after analyzing code, i found that you can use projection option, but it is tricky:

articles.find(
 { "$text" => { "$search" => "cake" } }, 
 projection: { 
   "score" => { "$meta" => "textScore" }, 
   some_field: 1
 })

My test was:

posts.find(
  { "$text" => { "$search" => "house" } }, 
  projection: { "score" => { "$meta" => "textScore" }, rooms: 1 }
)

Results is:

{"_id"=>BSON::ObjectId('53f5c8b54465764a82fb0000'), 
 "rooms"=>2.0, 
 "score"=>0.5004448398576512}
Comments