3

I have similar code as in PyMongo documentation on cursors here https://api.mongodb.org/python/current/api/pymongo/cursor.html

Here is the code from doc page.

cursor = db.test.find(
    {'$text': {'$search': 'some words'}},
    {'score': {'$meta': 'textScore'}})

When I run this code with Windows Python 2.7 PyMongo 3.0.3 and also 3.0.2 I get the following MongoDB error "OperationFailure: database error: Can't canonicalize query: BadValue unknown operator: $meta". Looking at the cause I was able reproduce this error if I use MongoDB client and put "{'score': {'$meta': 'textScore'}}" before "$text", like this.

db.test.find({ score: { $meta: "textScore" } }, { $text: { $search: "some words" }})

Back in Python, if I print dictionary with query keys I see "score" key first and "$text" key second. I guess this is causing PyMongo to form wrong query and subsequently an error in find methos.

Is there a work around for this issue?

Thanks

  • When you say *"if I print dictionary with query keys"* that implies to me that your arguments to `.find()` are actually combing from another variable as a dictionary as opposed to how you say you are submitting the arguments. This will be the actual cause, due to A. You are not using an ordered dict B. You are submitting the wrong arguments for the function. See [`.find()`](http://api.mongodb.org/python/current/api/pymongo/collection.html#pymongo.collection.Collection.find) where I suspect you are not separating query from projection and placing in a single dict. – Blakes Seven Sep 14 '15 at 01:34
  • I store query in the dictionary first so I could print it and see its values. I tried to use OderedDict but the error does not go away. Here is how I use default dictionary and find - pretty straight forward. search = {} search['$text'] = {'$search': 'lighting installation'} search['score'] = { '$meta': 'textScore' } test.db.find(search) – user3120928 Sep 14 '15 at 01:48
  • And that is where you are going wrong. The dict you are using is not ordered and/or you have combined query and projection in a single dict. If you still don't understand then include the actual code defining and using this so we can point out the error explicitly. – Blakes Seven Sep 14 '15 at 01:51

2 Answers2

1

you don't need a work around your first example should work I tested it with pymongo 3.0.3 and works just find.

db.test.find({'$text': {'$search': 'some words'}}, {'score': {'$meta': 'textScore'}})

Now, second example it fails because you switch the position of two positional arguments.

Talking about Python's unordered dictionaries makes no sense here because we are talking about two different dictionaries with a single key. I don't understand how you can get "score" key first and "$text" key second when we are talking about two dictionaries, except if you combined the two which is wrong, and your first try is not what you pasted here.

(*) There are cases with pymongo where you will need to use an ordered dictionary as in some complicated queries, in that case you should use a BSON object (see here) . But you don't need this in your case.

Community
  • 1
  • 1
nickmilon
  • 1,332
  • 1
  • 10
  • 9
  • I believe this is a dictionary with two keys ("$text" and "score") each pointing to a single key ("search" and "$meta") dictionaries. Printing such dictionary, declared outside of find method, showed "score" key first, followed by "$text" key. Now, the fact that seeing this keys in such sequence is causing mentioned error is my speculation. After I inlined this dictionary into find method I stopped getting the error. I am new to MongoDB. My second example is trying to figure out why PyMongo gives me this error. So I fired native MongoDB client and issued command with "score" first. – user3120928 Sep 14 '15 at 05:46
-1

I found the solution to my problem. I stopped using dictionary variable and formed query dictionary right inside of find method, like this.

db.test.find({'$text': {'$search': 'some text'}}, {'score': {'$meta': 'textScore'}})

Looks like doing this way causes an issue, even if I use OrderedDict.

search = {}
search['$text'] = {'$search': 'some text'}
search['score'] = { '$meta': 'textScore' }
db.test.find(search)