Mongoengine - save only one embedded document

Viewed 296

I have a MongoDB document that is quite large, so it takes a few seconds to save. One of the fields is a list of embedded documents. When I update one of the items in the list, and I want to save to the database, I want to be able to save just the specific embedded document instead of the entire document.

An abbreviated part of my code is as follows:

class Paragraph(mongoengine.EmbeddedDocument):
    _id = mongoengine.ObjectIdField(required=True, default=lambda: ObjectId())
    text = mongoengine.StringField()
    updated = mongoengine.BooleanField()

class Contract(mongoengine.Document):
    paragraphs = mongoengine.ListField(mongoengine.EmbeddedDocumentField(Paragraph))

    def save(self, **kwargs):
        if kwargs.get('update_only', False):
            super(Contract, self).update(set__paragraphs=self.paragraphs)
        else:
            super(Contract, self).save(**kwargs)

So this code allows me to save only the paragraphs field in the Contract document, which is already a lot more efficient than saving the entire document. However, this still takes a while, as there are a lot of paragraphs in a document.

I added the attribute updated to Paragraph. I want to be able to save only those paragraphs that are marked as updated.

I found a way to do this by first removing all updated paragraphs from the database and then adding new ones.

Contract.objects(id=id).update_one(pull__paragraphs={'_id': id_of_updated_paragraph})
Contract.objects(id=id).update_one(add_to_set__paragraphs=updated_paragraph)

This still feels like very inefficient. Is there a better way to do this?

1 Answers

Okay so, I know mongodb isn't used to be used as a relational database, but it can, and sometimes it's needed.

It seems like this is one of those times that it is. Let me explain why. Although in your example, all the paragraphs only matter in a specific contract, you are modifying the paragraph objects more frequently than you modify your contract object.

Breaking each paragraph into its own document will give you the dynamic behavior you are looking for, you will be able to update specific paragraphs without touching the Contract object.

You will also be able to delete paragraphs, and change their orders much easily by only changing the Contract object.

Btw, if this is your only object, I would even suggest you moving to a SQL database, it seems like it's more suitable for your need.

Related