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
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)