adnanmuttaleb
adnanmuttaleb

Reputation: 3624

How to do atomic Read–modify–write in mongoengine?

Basically I have Post Document and Comment EmbeddedDocument as follow:

class Comment(EmbeddedDocument):
    value1 = StringField(max_length=200,)
    value2 = StringField(max_length=200,)
    value3 = StringField(max_length=200,)
    id = UUIDField(required=True, primary_key=True)

class Post(Document,):
    comments = EmbeddedDocumentListField(Comment, required=False) 

PUT request may update any combination of value1, value2 and value3 for a given comment of a given post. I use queryset update method to do that as follow:

post = Post.objects.get(id=post_id)
comment = None
for comm in post.comments:
    if comm.id == comment_id:
        comment = comm

Post.objects(
    id=post_id, 
    comments__id=comment_id
).update(
        set__comments__S__value1=new_value1 or comment.value1,
        set__comments__S__value2=new_value2 or comment.value2,
        set__comments__S__value3=new_value3 or comment.value3,
)

But this clearly not Read–modify–write atomic operation. So hot Read–modify–write as one atomic operation?

Upvotes: 0

Views: 784

Answers (1)

Peter
Peter

Reputation: 1253

The positional operator allows you to update list items without knowing the index position, therefore making the update a single atomic operation.

The positional operator (set__comments__S__value1) allows you to update exact comment, that will be selected by comments__id=comment_id. That means you no need cycle to get the comment. You can do everything with one operation.

Documents may be updated atomically by using the update_one(), update() and modify() methods on a QuerySet or modify() and save() (with save_condition argument) on a Document.

Detailed here

Code to update only one Comment with given id:

def put(value1=None, value2=None, value3=None):
   data = {}
   if value1:
       data['set__comments__S__value1'] = value1
   if value2:
       data['set__comments__S__value2'] = value2
   if value3:
       data['set__comments__S__value3'] = value2
   Post.objects(
       id='5dab09cade20c4423a9cb4d1', 
       comments__id='18f75928-36d5-415d-b8a9-18488f954e68'
   ).update(**data)

Upvotes: 1

Related Questions