Updating a list of embedded documents in mongoengine
No with list field you cannot do an upsert into a list in a single query. $addToSet
wont work as you've changed the post
so you cant match. You can code round this but it does create a race condition where there is a small window of opportunity for error eg:
class Post(EmbeddedDocument): uid = StringField(required=True) text = StringField(required=True) class Feed(Document): label = StringField(required=True) feed_url = StringField(required=True) posts = ListField(EmbeddedDocumentField(Post)) Feed.drop_collection() Feed( label="label", feed_url="www.feed.com" ).save() post = Post(uid='1', text="hi") updated = Feed.objects(posts__uid=post.uid).update_one(set__posts__S=post) if not updated: Feed.objects.update_one(push__posts=post)
First we try to update and if it doesn't exist we push to the list - this is where there is a window of opportunity for another process to run and potentially push the post
on the list.
The risk might be acceptable but realistically, I think changing your schema is better, potentially splitting Post
out into its own collection. Then you can use an update statement and set the whole object. The cost will be an extra query to get the feed data.
Feed.objects.filter(posts__uid=post.uid).\ update_one(push__posts__S__comments='comment demo')