【发布时间】:2018-09-22 10:17:50
【问题描述】:
我目前有一些 id 作为 UUID 存储在 Mongo 中(处理所必需的)。他们得到这样的回报:
"_id" : new BinData(3, "JliB6gIMRuSphAD2KmhzgQ==")
有什么简单的方法可以将此值转换为字符串以进行调试?
要明确一点 - 应用程序可以很好地处理数据。我只需要一种快速从 Mongo 获取实际 UUID 的方法。
【问题讨论】:
标签: mongodb
我目前有一些 id 作为 UUID 存储在 Mongo 中(处理所必需的)。他们得到这样的回报:
"_id" : new BinData(3, "JliB6gIMRuSphAD2KmhzgQ==")
有什么简单的方法可以将此值转换为字符串以进行调试?
要明确一点 - 应用程序可以很好地处理数据。我只需要一种快速从 Mongo 获取实际 UUID 的方法。
【问题讨论】:
标签: mongodb
您的问题的答案比您预期的要复杂!它复杂的主要原因是由于历史原因(不幸的是)不同的驱动程序使用不同的字节顺序将 UUID 写入数据库。您没有提及您使用的是哪个驱动程序,但我将使用 C# 驱动程序作为示例。
假设我使用以下代码插入一个文档:
var guid = new Guid("00112233-4455-6677-8899-aabbccddeeff");
collection.Insert(new BsonDocument {
{ "_id", guid },
{ "x", 1 }
});
如果我随后使用 Mongo shell 检查文档,它看起来像这样:
> db.test.findOne()
{ "_id" : BinData(3,"MyIRAFVEd2aImaq7zN3u/w=="), "x" : 1 }
>
Mongo shell 有一个名为 hex 的内置函数,您可以使用它来将二进制值显示为十六进制字符串:
> var doc = db.test.findOne()
> doc._id.hex()
33221100554477668899aabbccddeeff
>
仔细看:十六进制字符串的字节顺序与 C# 程序中使用的原始 UUID 值不匹配。这是因为 C# 驱动程序使用 Microsoft 的 Guid 类的 ToByteArray 方法返回的字节顺序(遗憾的是,它以奇怪的顺序返回字节,这个事实已经好几个月没有被发现了)。其他司机也有自己的特点。
为了解决这个问题,我们有一些用 Javascript 编写的帮助函数,可以加载到 Mongo shell 中。它们在此文件中定义:
https://github.com/mongodb/mongo-csharp-driver/blob/master/uuidhelpers.js
可以通过在命令行上提供文件名(以及 --shell 参数)来告诉 Mongo shell 在启动时处理文件。加载此文件后,我们可以访问许多帮助函数来创建和显示作为 UUID 的 BinData 值。例如:
C:\mongodb\mongodb-win32-x86_64-2.0.1\bin>mongo --shell uuidhelpers.js
MongoDB shell version: 2.0.1
connecting to: test
type "help" for help
> var doc = db.test.findOne()
> doc._id.toCSUUID()
CSUUID("00112233-4455-6677-8899-aabbccddeeff")
> db.test.find({_id : CSUUID("00112233-4455-6677-8899-aabbccddeeff")})
{ "_id" : BinData(3,"MyIRAFVEd2aImaq7zN3u/w=="), "x" : 1 }
>
在此示例中,toCSUUID 函数用于将 BinData 值显示为 CSUUID,CSUUID 函数用于使用 C# 驱动程序的字节顺序约定为 UUID 创建 BinData 值,以便我们可以查询 UUID。其他驱动程序(toJUUID、toPYUUID、JUUID、PYUUID)也有类似的功能。
在未来的某一天,所有驱动程序都将在具有标准字节顺序的新二进制子类型 4 上进行标准化。与此同时,您必须使用与您正在使用的任何驱动程序相匹配的适当帮助函数。
【讨论】:
{"$uuid":"00112233-4455-6677-8899-aabbccddeeff"}
在查询之前使用此函数:
function ToGUID(hex) {
var a = hex.substr(6, 2) + hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2);
var b = hex.substr(10, 2) + hex.substr(8, 2);
var c = hex.substr(14, 2) + hex.substr(12, 2);
var d = hex.substr(16, 16);
hex = a + b + c + d;
var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
return '"' + uuid + '"';
}
var id = new BinData(3, "JliB6gIMRuSphAD2KmhzgQ==");
ToGUID(id.hex());
结果:
"ea815826-0c02-e446-a984-00f62a687381"
【讨论】:
如果你使用的是Java spring-data,你可以使用这个算法:
function ToUUID(hex) {
var msb = hex.substr(0, 16);
var lsb = hex.substr(16, 16);
msb = msb.substr(14, 2) + msb.substr(12, 2) + msb.substr(10, 2) + msb.substr(8, 2) + msb.substr(6, 2) + msb.substr(4, 2) + msb.substr(2, 2) + msb.substr(0, 2);
lsb = lsb.substr(14, 2) + lsb.substr(12, 2) + lsb.substr(10, 2) + lsb.substr(8, 2) + lsb.substr(6, 2) + lsb.substr(4, 2) + lsb.substr(2, 2) + lsb.substr(0, 2);
hex = msb + lsb;
var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
return uuid;
}
【讨论】:
def binaryToUUID(byte: Array[Byte]): String = {
if (byte == null) null
else {
val bb = ByteBuffer.wrap(byte)
new UUID(bb.getLong, bb.getLong()).toString
}
}
【讨论】: