pythonmongodbmongoengine

MongoEngine upsert and append to ListField of IntChoiceField (append to list if record exists, create otherwise)


I have the following definition for an IntChoiceField:

from mongoengine import IntField


class IntChoiceField(IntField):
    def __init__(self, min_value=None, max_value=None, choices: list = None, **kwargs):
        super().__init__(min_value, max_value, **kwargs)
        self.choices = self.validate_choices(choices=choices)

    def validate_choices(self, choices: list):
        try:
            choice_map = dict(choices)
            choice_list = list(choice_map)
            choice_list.sort()
            return choice_list
        except TypeError:
            self.error("Choice list is not valid!")

    def validate(self, value):
        super().validate(value)
        if value not in self.choices:
            self.error("Invalid Choice")

Now I have a collection like this:

import mongoengine_goodjson as gj
class Collection(gj.Document):
    TYPE_1 = 1
    TYPE_2 = 2
    TYPE_3 = 3
    TYPES = [
        (TYPE_1, "type_1"),
        (TYPE_2, "type_2"),
        (TYPE_3, "type_3"),
    ]

    user_id = ObjectIdField()
    types = ListField(IntChoiceField(choices=TYPES))

I want to lookup on user_id and create a new record if nothing is found, or update and append to the list of types if a record is found. Upserting the first found record is also fine.

I figured I could do something like this:

Collection(user_id=user_id).update(add_to_set__types=1, upsert=True)

or this:

Collection(user_id=user_id).update(push__types=1, upsert=True)

but in both cases, always a new record is created regardless of its existence. How I can upsert and append on update?


Solution

  • I don't know why these don't work:

    Collection(user_id=user_id).update(add_to_set__types=1, upsert=True)
    Collection(user_id=user_id).update(push__types=1, upsert=True)
    

    but this works:

    Collection.objects(user_id=user_id).update_one(add_to_set__types=1, upsert=True)