64

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.

David Neale
  • 16,498
  • 6
  • 59
  • 85

5 Answers5

88

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.

Robert Stam
  • 12,039
  • 2
  • 39
  • 36
  • That's just what I was looking for, thanks! I had no idea of the history behind this. – David Neale Nov 24 '11 at 14:13
  • Did I dream this, or didn't there use to be another way to do it? E.g. `{"$uuid":"00112233-4455-6677-8899-aabbccddeeff"}` – nilskp Oct 23 '12 at 21:30
  • 10
    sweet holy ghost this is absurd. Thank you though. – Robert Christ Sep 02 '14 at 21:26
  • 3
    If you're using RoboMongo, this article tells you how to enable uuidhelpers.js: http://robomongo.org/articles/uuids.html – Paul Keister May 14 '15 at 16:20
  • 1
    Thanks, the Mongo team seem to have decided not to write any documentation on the BinData object... – Frayt Nov 13 '19 at 10:25
  • 2
    This is an old answer so it's understandable, but I just want to save people time and say that the hex() function appears to no longer be supported. I am seeking an alternative. – dyslexicanaboko Jan 18 '23 at 00:56
15

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"

Todd
  • 1,071
  • 8
  • 12
  • How to do the conversion the other way around i.e from GUID/UUID string to Binary? – user3495691 Apr 28 '21 at 05:48
  • 1
    @user3495691 The conversion from GUID/UUID string to Binary is [here](https://stackoverflow.com/a/38920080/2436809) – Todd May 16 '21 at 20:01
7

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;
}
Leonardo
  • 3,141
  • 3
  • 31
  • 60
0
def binaryToUUID(byte: Array[Byte]): String = {

  if (byte == null) null

  else {
    val bb = ByteBuffer.wrap(byte)
    new UUID(bb.getLong, bb.getLong()).toString
  }
}
Renan Araújo
  • 3,533
  • 11
  • 39
  • 49
knowledge_seeker
  • 362
  • 3
  • 20
0

If your mongodb driver uses javascript, then you could try this to get hex:

BinData(3,"ABEiM0RVZneImaq7zN3u/w==").toString('hex');
abisammy
  • 554
  • 4
  • 12
asipes
  • 1
  • 1