1

I have problems with queries on UUID filed in my mongo collection. Mongo document structure is like:

{
    "_id": {
        "$oid": "5acf7faff5f02b0001e9fda1"
    },
    "j": {
        "$uuid": "d0459793-3ec0-71fd-319e-b959af081db6"
    },
    "s": "ok",
    "creation_date": {
        "$date": "2018-04-12T15:47:59.003Z"
    }
}

I want to get document, passing j uuid (not ObjectID). I create mongo connection, and I get my collection, then I try to execute this query:

import (    
       mgo "gopkg.in/mgo.v2"
       "gopkg.in/mgo.v2/bson"
)
...
var job *Job
uid, _ := uuid.FromString(m.ID)
e := c.Find(bson.M{"j": uid.String()}).One(&job)

but e is always equal to "not found".

m.ID is string of uuid without dashes- so I convert it to uuid.UUID.

Other queries like c.Find(bson.M{"s": "ok"}).All(&jobs) work fine, so I'm sure about connection & collection.

Using golang 1.11 & mongodb 3.6.

UPDATE:

When I do db.mycol.find() from mongo console result is a list of documents like:

{ "_id" : ObjectId("5acf5b0ac7fb0700010040ac"), "j" : BinData(3,"amOjUW1oQQ6dNsvLrQuDhg=="), "s" : "ok", "creation_date" : ISODate("2018-04-12T13:11:38.365Z") }

so I tried to modify my query like this:

e := c.Find(bson.M{"j": bson.Binary{0x03, []byte(m.ID)}}).One(&job)

And still it does not return the document.

icza
  • 389,944
  • 63
  • 907
  • 827
sheshkovsky
  • 1,302
  • 3
  • 18
  • 41

3 Answers3

2

The j property in your MongoDB documents is of type BinData type 3, so using a filter where you match it against a string will never yield any results.

Your second attempt is on the right track. Except that you are filtering for the UTF-8 byte sequences of the hex representation of the UUID string (this is how Go stores strings in memory, this is what a string -> []byte conversion yields). This again will never yield any results.

And the reason is that the binary data you have to provide in bson.Binary is not the above mentioned value, but the raw bytes of the UUID.

So what you have to do is hex-decode the UUID (which is given to you as the hex representation), and use this binary data.

data, err := hex.DecodeString(m.ID)
if err != nil {
    panic(err)
}

e := c.Find(bson.M{"j": bson.Binary{
    Kind: bson.BinaryUUIDOld,
    Data: data,
}}).One(&job)

Note that you have to pass the UUID to hex.DecodeString() without dashes, so you don't even need any 3rd party libs to process the UUID strings you have.

Also please note that gopkg.in/mgo.v2 is not maintained anymore. Instead use the community supported fork: github.com/globalsign/mgo.

icza
  • 389,944
  • 63
  • 907
  • 827
  • I've never had to do this and I've used UUID with Mongo pretty extensively. It seems to work fine just passing the UUID directly (not converted to string or wrapped in `bson.Binary`). – Adrian Sep 05 '18 at 15:02
  • @Adrian If the value stored in MongoDB is a `bson.UUID` value, filtering by the hex UUID string will not match it (not with the dashed version, nor without dashes), neither will filtering by the raw byte slice (I've tried all these). Maybe in your case the value stored in the database was just a string value or raw binary data and not of type `bson.UUID`? – icza Sep 05 '18 at 15:17
  • The hex UUID string will not match it, no - hence my saying *not* converted to string. The raw binary data should match - i.e., if you use the same data type you put in the field to upsert the document to query that field, it should work with no additional conversion. – Adrian Sep 05 '18 at 15:38
  • Not sure what you mean - `bson.UUID` is never mentioned in the question or OP's comments, BSON has no UUID type natively (it has ObjectID, which is similar but not technically a UUID), and the quoted document's `j` field is `BinData` type 3 (object), not type 7 (object ID). – Adrian Sep 05 '18 at 16:58
  • @Adrian You're right, my wording was unclear / confusing. Removing those comments. – icza Sep 05 '18 at 17:53
1

If you have GUID to query with, following conversion worked for me (reorders the key bytes and then converts to hex decode):

func CsuuidToBinary(key string) []byte {
    hexStr := strings.Replace(key, "-", "", -1)
    first := hexStr[6:8] + hexStr[4:6] + hexStr[2:4] + hexStr[0:2]
    second := hexStr[10:12] + hexStr[8:10]
    third := hexStr[14:16] + hexStr[12:14]
    fourth := hexStr[16:len(hexStr)]
    hexStr = first + second + third + fourth

    data, _ := hex.DecodeString(hexStr)
    return data
}

and then:

    data := CsuuidToBinary(guidKey)

    var a A
    err := collection.Find(bson.M{"SomeKey": bson.Binary{Kind: 0x03, Data: data,}}).One(&a)
Kunal
  • 125
  • 1
  • 5
0

This is because the UUID is stored as binary data and you need to convert that to string in order to query it

Look at this answer on how to convert mongo bindata to string and modify your FromString

Get BinData UUID from Mongo as string

rajeshnair
  • 1,587
  • 16
  • 32