How to do "insert if not exist else update" with mongoengine?
Asked Answered
C

5

28

I'm working with mongoengine in Django,
this is my document defination:

class Location(mongoengine.Document):  
    user_id = mongoengine.IntField(required=True)  
    point = mongoengine.GeoPointField(required=True)

I want to do this:
given a user_id and a point:
if there is no document that have this user_id, create one with the user_id and point and save it;
else update the document with user_id with point.
Can I do this in one statement with mongoengine?

Collen answered 9/12, 2011 at 15:10 Comment(2)
possible duplicate of mongodb: insert if not exists - The answer is: use upsert.Immersion
@Immersion I think there maybe something even simpler.Collen
Y
47

Note that get_or_create is now scheduled to be deprecated, because with no transaction support in MongoDB it cannot ensure atomicity.

The preferred way is update with upsert:

Location.objects(user_id=user_id).update_one(set__point=point, upsert=True)

More on upserts on the MongoDB documentation.

Yaya answered 19/4, 2013 at 8:44 Comment(4)
How can I do the same thing but with user_id==-1 when the object does not exist?Canalize
@Canalize with MongoDB, the object ID for a new document is generated client-side, so you just need to create a new ID with user_id= ObjectId().Yaya
There is a new way to do it since version 0.9 (explained here): location = Location.objects(user_id=user_id).modify(upsert=True, new=True, set__point=point)Canalize
There is upsert_one method too: docs.mongoengine.org/…Marks
C
9

There is a new way to do it since version 0.9 (explained here):

location = Location.objects(user_id=user_id).modify(upsert=True, new=True, set__point=point)

It returns the created or updated object.

Canalize answered 20/1, 2015 at 12:56 Comment(0)
C
5

this is what I came up with:

location = Location.objects.get_or_create(user_id=user_id)[0]  
location.point = point  
location.save()
Collen answered 9/12, 2011 at 15:45 Comment(2)
location, created = Location.objects.get_or_create(user_id=user_id) Is the preferred way of doing it! But yes that will do what you need!Confederate
get_or_create() is now deprecated. upsert is recommended by the Mongoengine crew. See @NCao's answer for more info.Declaratory
A
1

Or you can add a method to your class object via:

class Location(mongoengine.Document):  
    user_id = mongoengine.IntField(required=True)  
    point = mongoengine.GeoPointField(required=True)

    def register(self):
        # if doesnt exist, create user id and point field
        if not Location.objects(user_id=self.user_id):
            self.user_id = self.user_id
            self.point = self.point
            self.save()
            return True
        # does exist, do nothing
        else:
            return False
Almaalmaata answered 17/9, 2019 at 15:37 Comment(1)
What's the reason for the lines self.user_id = self.user_id self.point = self.point? ThanksIdiocy
B
0

My solution to update of not exist was this:

    def upsert(self, data: dict, query: dict):
        try:
            sets = {}
            for key in data.keys():
                sets[f"set__{key}"] = data[key]
            response = self.model.objects(**query).update_one(upsert=True, **sets)
            return response
        except Exception as ex:
            # Logger(str(ex)).log_error()
            return False

or if you want, you can use the method update.

Blizzard answered 2/4, 2022 at 21:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.