In [2]:
import bsonsearch

In [3]:
bc = bsonsearch.bsoncompare()

The standard libbson library cannot recurse into main.sub.third in document like the one below.

You could explicitly call every document using the convert_to_and helper function to turn

{"main.sub.third":3}

into

{"$or": [{"main.0.sub.third": 3}, {"main.1.sub.0.third": 3}, {"main.1.sub.1.third": 3}]}

This forces the library to create (and destroy) a new matcher object per document (nearly doubling the overhead)


In [7]:
%%timeit
from bson import json_util
spec = {"main.sub.third":3}
doc = {"main":[{"sub":{"third":2}},{"sub":[{"third":2}, {"third":3}]}]}
doc_id = bc.generate_doc(doc)
newspec = bc.convert_to_and(spec, doc_id)['$and'][0]
matcher= bc.generate_matcher(newspec)
found = bc.match_doc(matcher, doc_id)
bc.destroy_matcher(bc.matchers)
bc.destroy_doc(doc_id)
#print found


10000 loops, best of 3: 72.1 µs per loop

libbsoncompare now also support mongodb consistent searching

so you no longer need to call the convert_to_and function.

!However!, in doing this, it no longer supports mongodb queries where you can specify a compare against an individual item in the list. I never used or needed this functionality. Even through it doesn't make sense, in MongoDB logic, if you're looking for a specific item in a list, you should be storing as a list of subdocuments. I'd be more interested if someone had a legitimate reason for that function anyway.

Anyhoo, this works now, without creating a new matcher every document, AND cuts the compare time in half.


In [8]:
%%timeit
spec = {"main.sub.third":3}
doc = {"main":[{"sub":{"third":2}},{"sub":[{"third":2}, {"third":3}]}]}
doc_id = bc.generate_doc(doc)
matcher= bc.generate_matcher(spec)
found = bc.match_doc(matcher, doc_id)
bc.destroy_matcher(bc.matchers)
bc.destroy_doc(doc_id)


10000 loops, best of 3: 34.9 µs per loop