Sling Academy
Home/Python/MongoEngine Upsert: Insert if not exists, update if exists

MongoEngine Upsert: Insert if not exists, update if exists

Last updated: February 10, 2024

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.

Next Article: MongoEngine: AND & OR Conditions – Tutorial & Examples

Previous Article: MongoEngine: How to delete documents by a condition

Series: Data Persistence in Python – Tutorials & Examples

Python

You May Also Like

  • Python Warning: Secure coding is not enabled for restorable state
  • Python TypeError: write() argument must be str, not bytes
  • 4 ways to install Python modules on Windows without admin rights
  • Python TypeError: object of type ‘NoneType’ has no len()
  • Python: How to access command-line arguments (3 approaches)
  • Understanding ‘Never’ type in Python 3.11+ (5 examples)
  • Python: 3 Ways to Retrieve City/Country from IP Address
  • Using Type Aliases in Python: A Practical Guide (with Examples)
  • Python: Defining distinct types using NewType class
  • Using Optional Type in Python (explained with examples)
  • Python: How to Override Methods in Classes
  • Python: Define Generic Types for Lists of Nested Dictionaries
  • Python: Defining type for a list that can contain both numbers and strings
  • Using TypeGuard in Python (Python 3.10+)
  • Python: Using ‘NoReturn’ type with functions
  • Type Casting in Python: The Ultimate Guide (with Examples)
  • Python: Using type hints with class methods and properties
  • Python: Typing a function with default parameters
  • Python: Typing a function that can return multiple types