Search code examples
pythonmongodbmongoengine

Update a MongoEngine document using a python dict?


Is it possible to update a MongoEngine document using a python dict?

For example:

class Pets(EmbeddedDocument):
    name = StringField()

class Person(Document):
    name = StringField()
    address = StringField()
    pets = ListField(EmbeddedDocumentField(Pets))

p = Person()
p.update_with_dict({
    "name": "Hank",
    "address": "Far away",
    "pets": [
        {
            "name": "Scooter"
        }
    ]
})

Solution

  • Ok I just made a function for it.

    You call it like update_document(document, data_dict). It will loop through the items of data_dict and get the field instance using the key of the data_dict. It will then call field_value(field, value) where field is the field instance. field_value() will check the type of field using field.__class__ and based on that return a value that MongoEngine would expect. For example, the value of a normal StringField can just be returned as is, but for an EmbeddedDocumentField, an instance of that embedded document type needs to be created. It also does this trick for the items in lists fields.

    from mongoengine import fields
    
    
    def update_document(document, data_dict):
    
        def field_value(field, value):
    
            if field.__class__ in (fields.ListField, fields.SortedListField):
                return [
                    field_value(field.field, item)
                    for item in value
                ]
            if field.__class__ in (
                fields.EmbeddedDocumentField,
                fields.GenericEmbeddedDocumentField,
                fields.ReferenceField,
                fields.GenericReferenceField
            ):
                return field.document_type(**value)
            else:
                return value
    
        [setattr(
            document, key,
            field_value(document._fields[key], value)
        ) for key, value in data_dict.items()]
    
        return document
    

    Usage:

    class Pets(EmbeddedDocument):
        name = StringField()
    
    class Person(Document):
        name = StringField()
        address = StringField()
        pets = ListField(EmbeddedDocumentField(Pets))
    
    person = Person()
    
    data = {
        "name": "Hank",
        "address": "Far away",
        "pets": [
            {
                "name": "Scooter"
            }
        ]
    }
    
    update_document(person, data)