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:
- Perform the initial
$text
searching in a$match
stage - Persist the text score as part of the document via an
$addFields
stage - 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.