2012-09-12 11 views
9

Ich habe Probleme mit Mongoengine-Syntax.Aktualisieren einer Liste von eingebetteten Dokumenten in Mongoengine

Ich habe folgende Modelle ...

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 

... und mit dem Post-Objekt in weitergegeben my_method, würde Ich mag einen bestehenden Eintrag aktualisieren, wenn es mit einem in self.posts existiert passende UID, oder Push zu self.posts wenn nicht.

Gibt es Syntax, um das in einem Aufruf in Mongoengine zu tun?

Antwort

15

Nein mit Listenfeld Sie können keine Upsert in eine Liste in einer einzelnen Abfrage durchführen. $addToSet wird nicht funktionieren, wie Sie die post geändert haben, so dass Sie nicht übereinstimmen können. Sie können rund um diesen Code aber es hat eine Race-Bedingung zu schaffen, in dem sich ein kleines Fenster für Fehler zB der Möglichkeit ist:

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) 

Zuerst versuchen wir, zu aktualisieren und wenn es nicht schieben wir auf der Liste nicht vorhanden ist - das Ist dort, wo es ein Fenster der Gelegenheit gibt, damit ein anderer Prozess läuft und die post möglicherweise auf die Liste drückt.

Das Risiko könnte akzeptabel sein, aber realistisch, ich denke, Ändern Ihres Schemas ist besser, möglicherweise spalten Post in seine eigene Sammlung. Dann können Sie eine Update-Anweisung verwenden und das ganze Objekt setzen. Die Kosten werden eine zusätzliche Abfrage sein, um die Feed-Daten zu erhalten.

+0

Perfekt, danke! –

+0

@Ross Wie bekomme ich diese Antwort 'WriteResult ({" nMatched ": 0," nUpserted ": 0," nModified ": 0})' mit 'mongoengine'? Ich möchte überprüfen, ob der Artikel gefunden wurde. Vielen Dank –

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