Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoengine update_one+upsert vs. deprecated get_or_create

Suppose I have a collection of documents defined with MongoEngine as:

class Project(Document):
    name = StringField(required=True)
    client = StringField(required=True)
    code = StringField(required=True,unique=True)
    created = DateTimeField(required=True,default=datetime.datetime.now)

Historically, I could have used the get_or_create method to perform an "insert or update" type operation. For example:

Project.objects().get_or_create(name="Test Project One",
                                client="Client One",
                                code="CL1-001")

Which adds the following document to the collection:

{
    "name": "Test Project One",
    "client": "Client One",
    "code": "CL1-001",
    "created": {
        "$date": "2014-07-14T14:00:38.024Z"
    }
}

Now that this method has been depreciated the recommend alternative is to use update_one with upsert=True as follows:

Project.objects(code="CL1-002").update_one(set__name="Test Project Two",
                                           set__client="Client One",
                                           upsert=True)

But this results in a document being added to the collection without the created field:

{
    "client": "Client One",
    "code": "CL1-002",
    "name": "Test Project Two"
}

Is there is any way to replicate the get_or_create default field behaviour with MongoEngine without a race condition?

like image 694
Steve Rossiter Avatar asked Jul 14 '14 14:07

Steve Rossiter


1 Answers

This currently isn't supported automatically but it could be - please add a ticket and the maintainers can review.

In the meantime you can use $setOnInsert which only sets a value if it inserts and that will replicate whats needed eg:

Project.objects(code="CL1-002").update_one(set_on_insert__created=Project().created,
                                           set__name="Test Project Two",
                                           set__client="Client One",
                                           upsert=True)
like image 161
Ross Avatar answered Nov 15 '22 07:11

Ross