Query Embedded Document List in MongoEngine

Joey Hu picture Joey Hu · Apr 12, 2016 · Viewed 9.4k times · Source

I need query a list with all embedded documents in mongoengine. Here is my schema:

class Variant(EmbeddedDocument):
    name = StringField(required=True)
    value = StringField(required=True)

class Sku(Document):
    variants = ListField(EmbeddedDocumentField(Variant))

I can do it using mongo shell with:

db.sku.find({variants: [{'name': 'xxx', 'value': 'xxx'}]}).pretty()

But I haven't figure out a way to do it in mongoengine. I need the list in the document is exactly the same with the list I put in the query. Any ideas?

Answer

Blakes Seven picture Blakes Seven · Apr 12, 2016

Actually you were doing it "incorrectly" in the shell as well. The format you were using requires an exact match that would "rarely" actually match conditions. It certainly would not should the inner keys of the array be stored in a different order, or most importantly that the array itself actually stored more than one element.

The correct form for the "shell" would be:

db.sku.find({ "variants": { "$elemMatch": { "name": "xxx", "value": "xxx" } } })

By the same token, the "correct" form for MongoEngine is:

Sku.objects(variants__match={ "name": "xxx", "value": "xxx" })

The __match construct here is the same thing as, and actually issues an $elemMatch statement in query to the underlying MongoDB database as a query.

Note that for a "single" element condition the general "double underscore" syntax is just fine:

Sku.objects(variants__name="xxx")

But for "multiple" conditions and/or elements within the array/list, you need $elemMatch as a MongoDB query and therefore __match.