使用pymongo驱动程序裸连接python到mongodb,为什么使用ObjectId实例作为嵌入文档的密钥会引发InvalidDocument错误?
我正在尝试使用objectids链接文档,似乎无法理解为什么我想将它们转换为字符串时,为驱动程序自动创建的是ObjectId
个实例。
item = collection.find({'x':'foo'})
item['otherstuff'] = {pymongo.objectid.ObjectId() : 'data about this link'}
collection.update({'x':'foo'}, item)
bson.errors.InvalidDocument: documents must have only string keys, key was ObjectId('4f0b5d4e764df61c67000000')
在实践中,链接的ids表示包含问题的文档,例如,字典中的键值为“otherstuff”,表示该单个文档对该特定问题的回答。
有没有理由应用这样的objectids不会编码成bson然后失败?是否无法将ObjectIds嵌套在这样的文档中进行交叉引用?我误解了他们的目的吗?
答案 0 :(得分:6)
BSON spec表示密钥必须是字符串,因此PyMongo将此作为无效文档拒绝(并且无论在何种级别将ObjectId用作密钥,无论是在顶层还是在嵌入式文档中)。除了其他原因之外,这是必要的,以便查询语言可以是明确的。想象一下,你有这份文件(并且它是一份有效的BSON文件):
{ _id: ...,
"4f0cbe6d7f40d36b24a5c4d7": true,
ObjectId("4f0cbe6d7f40d36b24a5c4d7"): false
}
然后您尝试使用以下方式进行查询:
db.foo.find({"4f0cbe6d7f40d36b24a5c4d7": false})
这应该归还此文件吗?该字符串是否应自动装入ObjectId? Mongo如何知道什么时候可以自动装箱,以及如何在这样的文件中消除歧义?
问题的一种可能的替代解决方案是拥有一系列嵌入式文档,如:
{ answers: [
{ answer_id: ObjectId("..."), summary: "Good answer to this question" },
{ answer_id: ObjectId("..."), summary: "Bad answer to this question" }
]
}
这是有效的BSON,也可以更高效地编制索引。如果在answers
上添加索引,则可以有效地搜索这些子文档上的完全匹配项;如果你在answers.answer_id
上添加一个索引,那么你可以通过ObjectId有效地搜索你正在寻找的答案(等等)。