2012-09-12 56 views
9

我正在努力使用mongoengine語法。更新mongoengine中的嵌入式文檔列表

我有以下型號...

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 

...與傳遞到日誌對象my_method,我想更新現有的崗位,如果它與self.posts存在匹配uid,或者如果不是,則推送到self.posts。

在mongoengine的一個調用中是否有語法來做到這一點?

回答

15

否與列表字段不能在單個查詢中進行列表中的upsert。 $addToSet不會工作,因爲你已經改變了post,所以你不能匹配。您可以編寫這一輪,但它確實創造競爭條件哪裏有機會的錯誤如一個小窗口:

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) 

首先,我們嘗試更新,如果不存在的話,我們推到列表中 - 這是另一個進程運行的機會之窗,並有可能推動列表上的post

風險可能是可以接受但現實的,我認爲改變你的模式更好,可能會將Post分成它自己的集合。然後你可以使用更新語句並設置整個對象。成本將是一個額外的查詢來獲取供稿數據。

+0

完美,謝謝! –

+0

@Ross如何得到這個響應'WriteResult({「nMatched」:0,「nUpserted」:0,「nModified」:0})'使用'mongoengine'?我想檢查是否找到該項目。謝謝 –

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