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.