pymongo保存嵌入的objectIds,InvalidDocumentError

时间:2012-01-10 22:30:34

标签: python mongodb pymongo

使用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嵌套在这样的文档中进行交叉引用?我误解了他们的目的吗?

1 个答案:

答案 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有效地搜索你正在寻找的答案(等等)。