使用Mongoengine通过ID删除ListField项
我正在尝试通过目标列表项的 _id 从 ListField 中删除一个项目,使用的是 mongoengine。我参考了 mongoengine 的文档,关于原子更新的部分在这里:http://docs.mongoengine.org/guide/querying.html#atomic-updates
模型
class Prospect(db.Document):
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
class Comment(db.EmbeddedDocument):
_id = db.ObjectIdField(default=bson.ObjectId())
created_at = db.DateTimeField(default=datetime.datetime.now, required=True)
body = db.StringField(verbose_name="Note", required=True)
author = db.StringField(verbose_name="Name", max_length=255, required=True)
Mongo 文档看起来是这样的:
...
"comments": [
{
"_id": {
"$oid": "53bebb55c3b5a0db7829c15f"
},
"created_at": {
"$date": "2014-07-09T18:26:58.444Z"
},
"body": "Did something\n",
"author": "Dave Roma"
},
我想这样删除一个评论:
prospect = Prospect.objects(id=request.form['prospect_id']).update_one(pull___id=request.form['comment_id'])
但是我收到了一个 mongoengine 的 invalidQueryError 错误:
InvalidQueryError: Cannot resolve field "_id"
1 个回答
1
你问的问题的答案是:
prospect = Prospect.objects(id=request.form['prospect_id']).update_one(pull__comments__id=request.form['comment_id'])
你最开始的问题是想在mongoengine中找到_id
字段,但显然这个字段并不存在。
接下来是你在评论中提到的问题的解决方案。
解决方案 1:
class Prospect(db.Document):
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
def get_next_comment_id(self):
return len(self.comments)+1
def add_new_comment(self, author, body):
self.update(add_to_set__comments=Comment(_id=self.get_next_comment_id(), author=author, body=body)
class Comment(db.EmbeddedDocument):
_id = db.IntField(required=True)
created_at = db.DateTimeField(default=datetime.datetime.now, required=True)
body = db.StringField(verbose_name="Note", required=True)
author = db.StringField(verbose_name="Name", max_length=255, required=True)
上面的解决方案可能会失败,如果两个用户同时尝试添加新帖子,它们可能会有相同的_id
。在mongo的嵌入文档字段中,无法强制确保唯一性。你只能通过客户端代码来做到这一点。
解决方案 2:
创建一个单独的评论集合。
class Prospect(db.Document):
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
class Comment(db.Document):
on_prospect = db.ReferenceField(Prospect)
created_at = db.DateTimeField(default=datetime.datetime.now, required=True)
body = db.StringField(verbose_name="Note", required=True)
author = db.StringField(verbose_name="Name", max_length=255, required=True)
def add_new_comment(prospect, author, body):
comment = Comment(on_prospect = prospect, author=author, body=body).save()
return comment.id
def get_all_posts_on_prospect(prospect):
return Comment.objects(on_prospect = prospect).order_by('-id')
这样每个评论都会被分配一个唯一的ID。
解决方案 3:
这只是一个想法,我不太确定优缺点。
class Prospect(db.Document):
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
def get_id_for_comment(self, comment):
return self.comments.index(comment)
class Comment(db.EmbeddedDocument):
_id = db.IntField()
created_at = db.DateTimeField(default=datetime.datetime.now, required=True)
body = db.StringField(verbose_name="Note", required=True)
author = db.StringField(verbose_name="Name", max_length=255, required=True)
def add_new_comment(prospect, author, body)
comment = Comment(_id=self.get_next_comment_id(), author=author, body=body)
prospect.update(add_to_set__comments = comment)
cid = prospect.get_id_for_comment(comment)
prospect.update(set__comments__cid__id = cid)
return cid