Get BinData UUID from Mongo as string

Mongodb

Mongodb Problem Overview


I currently have some ids stored in Mongo as UUIDs (necessary for processing). They get returned like this:

"_id" : new BinData(3, "JliB6gIMRuSphAD2KmhzgQ==")

What would be an easy way to turn this value into a string for debugging?

Just to be clear - the application can handle the data fine. I just need a way to get the actual UUID from Mongo quickly.

Mongodb Solutions


Solution 1 - Mongodb

The answer to your question is more complicated that you would expect! The main reason it's complicated is that for historical reasons (unfortunately) different drivers have written UUIDs to the database using different byte orders. You don't mention which driver you are using, but I'll use the C# driver as an example.

Suppose I use the following code to insert a document:

var guid = new Guid("00112233-4455-6677-8899-aabbccddeeff");
collection.Insert(new BsonDocument {
    { "_id", guid },
    { "x", 1 }
});

If I then examine the document using the Mongo shell, it looks like this:

> db.test.findOne()
{ "_id" : BinData(3,"MyIRAFVEd2aImaq7zN3u/w=="), "x" : 1 }
>

The Mongo shell has a built-in function called hex that you can use to display the binary value as a hex string:

> var doc = db.test.findOne()
> doc._id.hex()
33221100554477668899aabbccddeeff
>

Look carefully: the byte order of the hex string doesn't match the original UUID value used in the C# program. That's because the C# driver uses the byte order returned by Microsoft's ToByteArray method of the Guid class (which sadly returns the bytes in a bizarre order, which fact was not discovered for many months). Other drivers have their own idiosyncracies.

To help out with this we have some helper functions written in Javascript that can be loaded into the Mongo shell. They are defined in this file:

https://github.com/mongodb/mongo-csharp-driver/blob/master/uuidhelpers.js

The Mongo shell can be told to process a file as it starts up by providing the name of the file on the command line (along with the --shell argument). Having loaded this file we have access to a number of helper functions to create and display BinData values that are UUIDs. For example:

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 }
>

In this example the toCSUUID function is used to display a BinData value as a CSUUID and the CSUUID function is used to create a BinData value for a UUID using the C# driver's byte ordering conventions so that we can query on a UUID. There are similar functions for the other drivers (toJUUID, toPYUUID, JUUID, PYUUID).

Some day in the future all drivers will standardize on a new binary subtype 4 with a standard byte order. In the meantime you have to use the appropriate helper function that matches whatever driver you are using.

Solution 2 - Mongodb

Use this function before your query:

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());

Result: "ea815826-0c02-e446-a984-00f62a687381"

Solution 3 - Mongodb

If you are using Java spring-data, you can use this algorithm:

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;
}

Solution 4 - Mongodb

def binaryToUUID(byte: Array[Byte]): String = {

  if (byte == null) null

  else {
    val bb = ByteBuffer.wrap(byte)
    new UUID(bb.getLong, bb.getLong()).toString
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid NealeView Question on Stackoverflow
Solution 1 - MongodbRobert StamView Answer on Stackoverflow
Solution 2 - MongodbToddView Answer on Stackoverflow
Solution 3 - MongodbLeonardoView Answer on Stackoverflow
Solution 4 - Mongodbknowledge_seekerView Answer on Stackoverflow