Skip to content
Advertisement

How can I limit text score with $gt operator in MongoDB?

I want to limit text scores using the $gt operator.

Using the find function, I can sort the text scores according to the text similarity status from largest to smallest. I can get the cursor with the highest score by putting a limit of 1 on the rank.


deneme = user.find(
   { '$text': { '$search': "dogan can" } },
   { 'score': { '$meta': "textScore" }})
    
deneme_sort  = deneme.sort([('score', {'$meta': 'textScore'})]).limit(1)


But I don’t want the ones whose text score is below the value I gave, to be listed.

For example, I don’t want text scores below 1.5 to appear in the list. I’m trying to use the ‘$gt’ operator for this but I’m getting an error.

deneme = user.find(
   { '$text': { '$search': "dogan can" } },
   { 'score': { '$meta': "textScore"}},  {'score': { '$gt': 1.5 } })


TypeError: skip must be an instance of int

it gives this error because the find function can only take two values.

I’m trying to query using the ‘$and’ operator. This time it does not recognize the ‘$meta’ operator. Or the ‘$gt’ operator must take two values.

deneme = user.find({ '$text': { '$search': "dogan can" }} ,
    {'$and':[{ 'score': { '$meta': "textScore" }},{'score': { '$gt': 1.5 }}]})

doc = []
for doc in deneme:
    print(doc)

Expression $gt takes exactly 2 arguments. 1 were passed in., full error: {'ok': 0.0, 'errmsg': 'Expression $gt takes exactly 2 arguments. 1 were passed in.', 'code': 16020, 'codeName': 'Location16020'}

I just started learning mongodb. Can you help me?

Advertisement

Answer

I think what you’re requesting is documented here. In short – you will need to use the aggregation framework so that you can have 3 stages to accomplish each of the following:

  1. Perform the initial $text searching in a $match stage
  2. Persist the text score as part of the document via an $addFields stage
  3. Use an additional $match stage to perform the $gt filtering against that new score field.

Given a collection with the following documents:

test> db.foo.find()
[
  { _id: 1, key: 'dogan can' },
  { _id: 2, key: 'dogan' },
  { _id: 3, key: 'can' },
  { _id: 4, key: 'abc' }
]

A text search against dogan can will return the first three documents:

test> db.foo.aggregate([ { $match: { $text: { $search: "dogan can" } } },{$addFields:{score:{$meta:'textScore'}}}])
[
  { _id: 3, key: 'can', score: 1.1 },
  { _id: 1, key: 'dogan can', score: 1.5 },
  { _id: 2, key: 'dogan', score: 1.1 }
]

Appending the final $match (using a filter of 1.2), only one of the documents is returned:

test> db.foo.aggregate([ { $match: { $text: { $search: "dogan can" } } },{$addFields:{score:{$meta:'textScore'}}},{$match:{score:{$gt:1.2}}}])
[ 
  { _id: 1, key: 'dogan can', score: 1.5 } 
]

If desired, you can of course include a $sort stage on the score as well.

6 People found this is helpful
Advertisement