通用唯一标识符 (UUIDs)
本页内容
概述
MongoDB 驱动程序在如何编码 通用唯一标识符 (UUIDs) 方面一直存在差异。在本指南中,您可以了解如何使用 PyMongo 的UuidRepresentation 配置选项,以在使用 UUIDs 时保持跨语言兼容性。
提示
在 MongoDB 应用程序中,您可以使用 ObjectId 类型作为文档的唯一标识符。在可能的情况下,请考虑使用 ObjectId 替代 UUID。
mongodb UUIDs简史
考虑以下规范文本表示的UUID
00112233-4455-6677-8899-aabbccddeeff
最初,MongoDB将UUID表示为BSON Binary 子类型3的值。因为子类型3在编码期间没有标准化UUID的字节序,所以不同的MongoDB驱动程序以不同的字节序编码UUID。使用以下选项卡比较不同MongoDB语言驱动程序将前面的UUID编码为Binary 子类型3的方式
00112233-4455-6677-8899-aabbccddeeff
33221100-5544-7766-8899-aabbccddeeff
77665544-3322-1100-ffee-ddccbbaa9988
为了标准化UUID字节序,我们创建了Binary 子类型4。尽管此子类型在MongoDB驱动程序中得到一致处理,但某些MongoDB部署仍包含子类型3的UUID值。
重要
在存储或检索子类型3的UUID时要小心。由一个MongoDB驱动程序存储的此类UUID值,当由不同的驱动程序检索时,可能具有不同的值。
指定UUID表示
为了确保您的PyMongo应用程序正确处理UUID,请使用UuidRepresentation选项。此选项确定驱动程序如何将UUID对象编码为BSON,以及如何从BSON解码Binary 子类型3和4值。
您可以通过以下方式设置UUID表示选项
在构建
MongoClient时传递uuidRepresentation参数。PyMongo使用指定的UUID表示对所有使用此MongoClient实例执行的操作进行编码。在MongoDB连接字符串中包含
uuidRepresentation参数。PyMongo使用指定的UUID表示对所有使用此MongoClient实例执行的操作进行编码。在调用
get_database()方法时传递codec_options参数。PyMongo使用指定的UUID表示对所有检索到的数据库执行的操作进行编码。在调用
get_collection()方法时传递codec_options参数。PyMongo 使用指定的 UUID 表示法执行所有检索集合的操作。
从以下选项卡中选择以查看如何指定前面的选项。有关可用的 UUID 表示法的更多信息,请参阅支持的UUID表示形式.
uuidRepresentation 参数接受在以下枚举中定义的值:UuidRepresentation。以下代码示例指定了 UUID 表示法的 STANDARD
from bson.binary import UuidRepresentation client = pymongo.MongoClient("mongodb://<hostname>:<port>", uuidRepresentation=UuidRepresentation.STANDARD)
uuidRepresentation 参数接受以下值
未指定标准pythonLegacyjavaLegacycsharpLegacy
以下代码示例指定 UUID 表示法的 standard
uri = "mongodb://<hostname>:<port>/?uuidRepresentation=standard" client = MongoClient(uri)
当调用 get_database() 方法以指定 UUID 格式时,创建 CodecOptions 类的实例,并将 uuid_representation 参数传递给构造函数。以下示例显示了如何使用 CSHARP_LEGACY UUID 格式获取数据库引用
from bson.codec_options import CodecOptions csharp_opts = CodecOptions(uuid_representation=UuidRepresentation.CSHARP_LEGACY) csharp_database = client.get_database("database_name", codec_options=csharp_opts)
提示
您还可以在调用 database.with_options() 方法时指定 codec_options 参数。有关此方法的更多信息,请参阅配置读写操作指南中的数据库和集合。
当调用 get_collection() 方法以指定 UUID 格式时,创建 CodecOptions 类的实例,并将 uuid_representation 参数传递给构造函数。以下示例显示了如何使用 CSHARP_LEGACY UUID 格式获取集合引用
from bson.codec_options import CodecOptions csharp_opts = CodecOptions(uuid_representation=UuidRepresentation.CSHARP_LEGACY) csharp_collection = client.testdb.get_collection("collection_name", codec_options=csharp_opts)
提示
您还可以在调用 collection.with_options() 方法时指定 codec_options 参数。有关此方法的更多信息,请参阅配置读写操作指南中的数据库和集合。
支持的UUID表示形式
以下表格总结了PyMongo支持的UUID表示形式
UUID表示形式 | 将 UUID编码为 | 将 Binary子类型4解码为 | 将 Binary子类型3解码为 |
|---|---|---|---|
UNSPECIFIED(默认) | 引发 ValueError | Binary子类型4 | Binary子类型3 |
Binary子类型4 | UUID | Binary子类型3 | |
Binary子类型3(标准字节序) | Binary子类型4 | UUID | |
Binary子类型3(Java遗产字节序) | Binary子类型4 | UUID | |
Binary子类型3(C#遗产字节序) | Binary子类型4 | UUID |
以下部分更详细地描述了前面的UUID表示形式选项。
UNSPECIFIED
注意
UNSPECIFIED是PyMongo中的默认UUID表示形式。
当使用UNSPECIFIED表示形式时,PyMongo将BSON Binary值解码为相同子类型的Binary对象。要将Binary对象转换为本地UUID对象,请调用Binary.as_uuid()方法并指定UUID表示形式格式。
如果您尝试在此表示形式下编码UUID对象,PyMongo将引发ValueError。为了避免这种情况,可以在UUID上调用如以下示例所示的Binary.from_uuid()方法。
explicit_binary = Binary.from_uuid(uuid4(), UuidRepresentation.STANDARD)
以下代码示例显示了如何检索包含UNSPECIFIED表示形式的UUID的文档,然后将该值转换为UUID对象。为此,代码执行以下步骤
使用
CSHARP_LEGACYUUID 表示法插入包含uuid字段的文档。使用
UNSPECIFIED表示法检索相同的文档。PyMongo 将uuid字段的值解码为Binary对象。调用
as_uuid()方法将uuid字段的值转换为类型为CSHARP_LEGACY的UUID对象。转换后,此值与 PyMongo 插入的原始 UUID 相同。
from bson.codec_options import CodecOptions, DEFAULT_CODEC_OPTIONS from bson.binary import Binary, UuidRepresentation from uuid import uuid4 # Using UuidRepresentation.CSHARP_LEGACY csharp_opts = CodecOptions(uuid_representation=UuidRepresentation.CSHARP_LEGACY) # Store a legacy C#-formatted UUID input_uuid = uuid4() collection = client.testdb.get_collection('test', codec_options=csharp_opts) collection.insert_one({'_id': 'foo', 'uuid': input_uuid}) # Using UuidRepresentation.UNSPECIFIED unspec_opts = CodecOptions(uuid_representation=UuidRepresentation.UNSPECIFIED) unspec_collection = client.testdb.get_collection('test', codec_options=unspec_opts) # UUID fields are decoded as Binary when UuidRepresentation.UNSPECIFIED is configured document = unspec_collection.find_one({'_id': 'foo'}) decoded_field = document['uuid'] assert isinstance(decoded_field, Binary) # Binary.as_uuid() can be used to convert the decoded value to a native UUID decoded_uuid = decoded_field.as_uuid(UuidRepresentation.CSHARP_LEGACY) assert decoded_uuid == input_uuid
STANDARD
当使用 STANDARD UUID 表示法时,PyMongo 将本机 UUID 对象编码为子类型 4 的 Binary 对象。所有使用 STANDARD 表示法的 MongoDB 驱动程序以相同的方式处理这些对象,不更改字节顺序。
在所有新的应用程序中以及所有首次使用 MongoDB UUIDs 的应用程序中使用 STANDARD UUID 表示法。
PYTHON_LEGACY
PYTHON_LEGACY UUID 表示法对应于 PyMongo 旧版本(小于 v4.0)中使用的 UUID 的旧表示法。当使用 PYTHON_LEGACY UUID 表示法时,PyMongo 将本机 UUID 对象编码为子类型 3 的 Binary 对象,保留与 UUID.bytes 属性相同的字节顺序。
如果您从 MongoDB 读取的 UUID 是使用 PYTHON_LEGACY 表示法插入的,请使用 PYTHON_LEGACY UUID 表示法。以下两个条件都满足时,这将是正确的
UUID 是使用版本小于 v4.0 的 PyMongo 应用程序插入的。
插入 UUID 的应用程序未指定
STANDARDUUID 表示法。
JAVA_LEGACY
JAVA_LEGACY UUID 的表示形式对应于 MongoDB Java 驱动程序使用的 UUID 的旧表示形式。当使用 JAVA_LEGACY UUID 表示形式时,PyMongo 将原生 UUID 对象编码为具有 Java 旧字节序的 Binary 子类型 3 对象。
如果您从 MongoDB 读取的 UUID 是使用 JAVA_LEGACY 表示形式插入的,请使用 JAVA_LEGACY UUID 表示形式。以下两个条件都满足时,则为真
UUID 是使用 MongoDB Java 驱动程序的应用程序插入的。
应用程序未指定
STANDARDUUID 表示形式。
CSHARP_LEGACY
CSHARP_LEGACY UUID 的表示形式对应于 MongoDB .NET/C# 驱动程序使用的 UUID 的旧表示形式。当使用 CSHARP_LEGACY UUID 表示形式时,PyMongo 将原生 UUID 对象编码为具有 C# 旧字节序的 Binary 子类型 3 对象。
如果您从 MongoDB 读取的 UUID 是使用 CSHARP_LEGACY 表示形式插入的,请使用 CSHARP_LEGACY UUID 表示形式。以下两个条件都满足时,则为真
UUID 是使用 MongoDB .NET/C# 驱动程序的应用程序插入的。
应用程序未指定
STANDARDUUID 表示形式。
故障排除
ValueError: 无法对本地uuid.UUID对象进行编码,因为UUID表示为uuidrepresentation.unspecified
此错误是由于尝试将本地UUID对象编码为二进制对象,而UUID表示为UNSPECIFIED,如下代码示例所示
unspecified_collection.insert_one({'_id': 'bar', 'uuid': uuid4()}) Traceback (most recent call last): ... ValueError: cannot encode native uuid.UUID with UuidRepresentation.UNSPECIFIED. UUIDs can be manually converted to bson.Binary instances using bson.Binary.from_uuid() or a different UuidRepresentation can be configured. See the documentation for UuidRepresentation for more information.
相反,您必须显式使用Binary.from_uuid()方法将本地UUID转换为二进制对象,如下例所示
explicit_binary = Binary.from_uuid(uuid4(), UuidRepresentation.STANDARD) unspec_collection.insert_one({'_id': 'bar', 'uuid': explicit_binary})
API文档
要了解更多关于UUID和PyMongo的信息,请参阅以下API文档