Decode UUID(binary format) to bson/interface{}

I’m storing data with UUID as id format. It’s represented as binary in MongoDB.
My problem is, that while I decode a result from the DB, the id field is not decoding as UUID.
I’m not using structs here, if I use them, there is no problem, it decodes well.

In this scenario, I have generic repository(with interfaces, not with actual generics future)
So, we are decoding to bson objects

Go code;

//find by id

var response bson.M
	err := r.db.FindOne(ctx, bson.M{"_id": id}).Decode(&response)

	if err != nil {
		return nil, err
	}

	return &response, nil
//output (json response via http)
{
    "_id": {
        "Subtype": 0,
        "Data": "d1rWV3UZSNu/s6ii14EFsA=="
    },
    "email": "user@user.com",
    "name": "name2",
    "username": "username"
}
//expected output
{
    "_id": "513775c1-e34b-4ead-a886-03157f650336"
    "email": "user@email.com",
    "name": "john",
    "username": "johndoe"
}

@dante_karakaya that’s a great question! The reason the response format is different is that the UUID values are converted to the BSON “binary” type when inserted into MongoDB, then the Go Driver unmarshals those binary values into a primitive.Binary, which has the structure you’re seeing in the JSON output:

type Binary struct {
	Subtype byte
	Data    []byte
}

While the BSON specification and MongoDB support a UUID-specific binary subtype, the BSON library in the Go Driver currently doesn’t have any special support for that UUID-specific binary subtype, so you just end up with a primitive.Binary value. If you want to use that primitive.Binary value as the original UUID type, you have to convert it.

For example, assuming you’re using the github.com/google/uuid UUID library, you could convert the primitive.Binary value in the "_id" field to a uuid.UUID like this:

resID := response["_id"]
b, ok := resID.(primitive.Binary)
if !ok {
	return nil,
		fmt.Errorf("expected response field _id to be type primitive.Binary, but is type %T", id)
}
uid, err := uuid.FromBytes(b.Data)
if err != nil {
	return nil, err
}

A potentially simpler alternative would be to convert the UUID values to strings when you insert them, and do the same when querying for them.

P.S. The Go Driver team is investigating improving usability of UUID values. Check out GODRIVER-2484 and leave any comments you have!

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.