2014년 12월 29일 월요일

PyMongo $in query with dictionaries

I am working with an _ID field that is a dictionary in my mongodb collection (e.g., _id : { 'a' : 1, 'b' : 2,  'a1': 3})

and I am trying to use the $in operator to query for results that match my key exactly. This works perfectly in the mongo shell, however, python dictionaries cannot be guaranteed an order and as a result the queries aren't returning results using pymongo. I've tried using bson.son.son and OrderedDict but haven't been able to get the query to click. 

The exact query I am trying to write is:
db.products.find({'_id': {'$in': [{'key1' : 2561, 'key4': '2561-99102605261', 'key2' : '99102605261'}, {'key1' : 2561, 'key4': '2561-99102605261', 'key2' : '99102605261'}]}})

This works 100% in mongo shell and is blazing fast. If I change this to jsut be an $in on _id.key(1|2|4) it will work but it returns in 700+ms whereas the query above returns instantaneously.

Any help would be greatly appreciated.

My python code looks like this

criteria = []
for item in data:
     criteria.append({ 'key1', item['key1'], 'key4', item['key4'], 'key2', item['key2'] })
self.db_instance.collection.find({'_id' : { '$in' : criteria}}, {"cat" : 1})

I have also tried using ordered collections as follows

import collections
criteria = []
for item in data:
     criteria.append(collections.OrderedDict({ 'key1', item['key1'], 'key4', item['key4'], 'key2', item['key2'] }))
self.db_instance.collection.find({'_id' : { '$in' : criteria}}, {"cat" : 1})

Any help would be greatly appreciated. Thanks!



Using collections.OrderedDict (or bson.son.SON) should get you the exact same query you used in the shell. Can you show the query and a bit of the output from the mongo shell, then the same query (using OrderedDict) and a bit of the output from the python shell? 



Apparently I was using collections.OrderedDict wrong. The line below worked

criteria = []
for item in data:
    criteria.append(collections.OrderedDict([('key1', 'a', ('key4', 'b'), ('key2', 'c')]))
self.db_instance.collection.find({'_id' : { '$in' : criteria}}, {"cat" : 1})



댓글 없음:

댓글 쓰기