0

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?

adnanmuttaleb
  • 3,388
  • 1
  • 29
  • 46

1 Answers1

1

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)
Peter
  • 1,223
  • 3
  • 11
  • 22
  • this is really not an answer, I can read the comment object in other ways, this does not matter, the question was how to make atomic read-modify-write. – adnanmuttaleb Oct 19 '19 at 15:31
  • Transactions do exact what you want: https://api.mongodb.com/python/current/api/pymongo/client_session.html#pymongo.client_session.ClientSession.with_transaction But it is not the best decision. The positional operator (set__comments__S__value1) allows you to update exact comment, that match by `comments__id=comment_id`. So, you no need find the comment separately to provide default values. I have edited my answer. – Peter Oct 19 '19 at 19:02