2012-09-12 10 views
9

Estoy luchando con la sintaxis de mongoengine.Actualizando una lista de documentos incrustados en 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 puesto a pasado a mi_metodo, me gustaría actualizar un puesto existente si existe en self.posts con una haciendo coincidir uid o push to self.posts si no es así.

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

Respuesta

15

No con el campo de lista no se puede hacer una inserción en una lista en una sola consulta. $addToSet no funcionará ya que ha cambiado el post por lo que no puede coincidir. Puede codificar esta ronda, pero crea una condición de carrera en la que 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 tratamos de actualizar y si no existe que empujar a la lista - esto es donde hay una ventana de oportunidad para que se ejecute otro proceso y potencialmente empujar el post en la lista.

El riesgo puede ser aceptable, pero de forma realista, creo que es mejor cambiar el esquema, posiblemente dividiendo Post en su propia colección. Luego puede usar una declaración de actualización y establecer el objeto completo. El costo será una consulta adicional para obtener los datos del feed.

+0

Perfecto, gracias! –

+0

@Ross cómo obtener esta respuesta 'WriteResult ({" nMatched ": 0," nUpserted ": 0," nModified ": 0})' usando 'mongoengine'? Quiero verificar si el artículo fue encontrado. Gracias –

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