MongoEngine Upsert: Insert if not exists, update if exists

Updated: February 10, 2024 By: Guest Contributor Post a comment

Introduction

When working with databases, a common requirement is to update a record if it exists or insert it as a new one if it doesn’t. This operation is commonly known as upsert, which stands for UPdate + inSERT. In the context of MongoDB, this can be achieved using the MongoEngine ODM (Object Document Mapper) in Python. This tutorial will guide you through implementing upserts with MongoEngine, progressing from basic to advanced usage, complete with code examples and expected outputs.

Getting Started with MongoEngine

Before diving into upserts, ensure you have MongoEngine installed and configured in your Python environment. Install MongoEngine using pip:

pip install mongoengine

Connect to your MongoDB instance:

from mongoengine import connect
connect('your_database_name', host='localhost', port=27017)

Basic Upsert Operation

Upserting with MongoEngine can be done using the update_one function with upsert=True. Here’s a simple example:

from mongoengine import Document, StringField, connect

class User(Document):
    name = StringField(required=True)
    email = StringField(required=True)

connect('user_db', host='localhost', port=27017)

user = {'name': 'John Doe', 'email': '[email protected]'}
User.objects(name=user['name']).update_one(upsert=True, **user)

This code checks if a user with the name ‘John Doe’ exists. If not, it inserts a new document with the provided ‘name’ and ’email’. If a document with such a name already exists, it will update the existing record.

Conditional Upsert

Let’s say you only want to perform an upsert based on certain conditions, such as updating the email of a user only if the current email matches a specific pattern. For this use case, you can utilize MongoEngine’s condition parameters:

user = {'name': 'Jane Doe', 'email': '[email protected]'}
User.objects(name=user['name'], email__icontains='@example.com').update_one(upsert=True, set__email=user['email'])

This updates ‘Jane Doe’s email only if the existing email contains ‘@example.com’. Otherwise, if no record matches the conditions, it inserts a new document.

Complex Upsert Scenarios

For more complex upsert operations involving embedded documents or arrays, you would typically use modify in conjunction with searching and updating or inserting as needed:

from mongoengine import EmbeddedDocument, EmbeddedDocumentField, ListField

class Address(EmbeddedDocument):
    street = StringField()
    city = StringField()

class Person(Document):
    name = StringField(required=True)
    addresses = ListField(EmbeddedDocumentField(Address))

connect('people_db', host='localhost', port=27017)

# Upsert an embedded document
person_name = 'Emily Clark'
new_address = {'street': '123 Elm Street', 'city': 'Gotham'}
Person.objects(name=person_name).modify(upsert=True, new=True, add_to_set__addresses=new_address)

This example uses modify with upsert=True and new=True to ensure that if a person named ‘Emily Clark’ does not exist, a new document is created. If she does exist, her document is updated by adding a new address to her ‘addresses’ list, provided it isn’t already present.

Conclusion

MongoEngine makes working with MongoDB in Python applications straightforward and efficient, particularly when it comes to upsert operations. Whether you’re dealing with simple record updates or complex scenarios involving embedded documents, following the steps outlined in this tutorial will help you implement upserts effectively. The power of upsert lies in its ability to keep your database concise and current without the need for separate insert and update operations.