Actualización de una lista de documentos incrustados en mongoengine

Estoy luchando con la syntax mongoengine.

Tengo los siguientes modelos …

class Post(EmbeddedDocument): uid = StringField(required=True) text = StringField(required=True) when = DateTimeField(required=True) class Feed(Document): label = StringField(required=True) feed_url = StringField(required=True) posts = ListField(EmbeddedDocumentField(Post)) def my_method(self, post): pass 

… y con el objeto de publicación pasado a my_method, me gustaría actualizar una publicación existente si existe en self.posts con un uid correspondiente, o empujar a self.posts si no es así.

¿Hay syntax para hacer eso en una llamada en mongoengine?

No con el campo de lista, no puede realizar una inserción en una lista en una sola consulta. $addToSet no funcionará, ya que ha cambiado la post por lo que no puede coincidir. Puede codificar esto, pero crea una condición de carrera donde hay una pequeña ventana de oportunidad para el error, por ejemplo:

  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) 

Primero intentamos actualizar y, si no existe, pasamos a la lista; aquí es donde hay una ventana de oportunidad para que se ejecute otro proceso y, posiblemente, empujemos la post en la lista.

El riesgo puede ser aceptable, pero de manera realista, creo que cambiar su esquema es mejor, ya que podría dividir la Post en su propia colección. A continuación, puede utilizar una instrucción de actualización y establecer todo el objeto. El costo será una consulta adicional para obtener los datos del feed.

 Feed.objects.filter(posts__uid=post.uid).\ update_one(push__posts__S__comments='comment demo')