Wednesday, November 4, 2015

A RoboMongo Trick

RoboMongo is a nice tool for digging around xDB databases. It provides the full feature set of the JavaScript shell (you can save variables, run help commands, etc.) and allows you to do things like edit documents directly through the JSON display.


One small annoyance, however, is that it is difficult to search by GUIDs.  Guids in MongoDB are a tricky business.  They are represented as binary objects, displayed by the format

BinData(3,"n1UNEaXe6kKcHIpd9+cO+Q==")

You can get at the underlying hex value by typing

BinData(3,"n1UNEaXe6kKcHIpd9+cO+Q==").hex()

which will give you

9f550d11a5deea429c1c8a5df7e70ef9

which looks a lot like a GUID. But is not one, for arcane historical reasons.  (Basically, Microsoft has a somewhat idiosyncratic way of arranging the bytes in the Guid.ToString() method.  More info here: http://stackoverflow.com/questions/3320501/why-isnt-guid-tostringn-the-same-as-a-hex-string-generated-from-a-byte-arra

The value BinData(3,"n1UNEaXe6kKcHIpd9+cO+Q==") actually corresponds 110d559f-dea5-42ea-9c1c-8a5df7e70ef9, the ID of the Sitecore Home item.  There are two ways you can make this conversion.  While using the Mongo shell, you can load the JavaScript file uuidhelpers.js (Save it to c:\tools\uuidhelpers.js, and then run load("c:\\tools\\uuidhelpers.js").  This will give you two useful functions:

CSUUID("some guid"), which generates a proper mongo BinData guid for your .NET Guid, and .toCSUUID(), which gives a GUID display for a BinData item:

BinData(3,"n1UNEaXe6kKcHIpd9+cO+Q==").toCSUUID()

returns

CSUUID("110d559f-dea5-42ea-9c1c-8a5df7e70ef9")

It's a nice feature of this script, and very keeping in the way MongoDB does things, that the representation of the GUID is in the form of the constructor for the BinData object. It makes round-tripping painless, since you can now do things like:

db.Interactions.findOne({"Page.Item._id": CSUUID("110d559f-dea5-42ea-9c1c-8a5df7e70ef9") })

Which makes a lot more sense then

db.Interactions.findOne({"Page.Item._id": BinData(3,"n1UNEaXe6kKcHIpd9+cO+Q==") })

to us Sitecore/.Net people.

Or you could use RoboMongo, which has a nifty Legacy UUID menu:



The .Net setting will display Guids like this:










This is an improvement, but still not ideal, as the NUUID value is not a JS constructor, so you can't use the Guid to query for docuemnts.

For example, this would not work to find all interactions that visited the home item:



Similarly, you cannot go from a contact ID here to one in the Contacts table, since you cannot use the displayed GUID field.   This is even a problem if you use Do Not Encode, which still displays the ID in a non-queryable format LUUID(" guid "), which will again return a not-defined JS error:



The way around this is simple. These formats only come into play if the variable is part of a larger JSON display.  If you query the value in isolation, you get the original BinData value:

db.Interactions.findOne().Pages[0].Item._id

returns a BinData representation:


You can also store this to a variable, like this:

var homeId = db.Interactions.findOne().Pages[0].Item._id

Which allows you to run queries like this one:

db.Interactions.find({"Pages.Item._id": homeId})

And now we have round-tripping. Also useful, as I mentioned above, for looking up contacts by ID in the db.Contacts collection.

No comments:

Post a Comment