2012-09-12 54 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')