我应该如何使用mgo处理UUID字段?

时间:2018-06-16 16:00:39

标签: mongodb go uuid mgo

我在MongoDB中有这个文档:

{
    "_id": {
        "$oid": "5ad0873b169ade0001345d34"
    },
    "j": {
        "$uuid": "94482b86-1005-e3a0-5235-55fb7c1d648a"
    },
    "v": "sign",
    "d": "a",
    "s": "init",
    "response": {},
    "creation_date": {
        "$date": "2018-04-13T10:32:27.140Z"
    }
}

我想过滤&使用mgo在Golang中获取一些文档,这里是我的代码:

package main

import (
    "fmt"
    "log"
    "time"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

type JOB struct {
   ID               bson.ObjectId       `bson:"_id,omitempty"`
   Key          string              `bson:"j"`
   Svc              string              `bson:"v"`
   DocType          string              `bson:"d"`
   Status           string              `bson:"s"`
   CreationDate     time.Time           `bson:"creation_date"`
}

func main() {
    session, err := mgo.Dial("mongodb://...")
    if err != nil {
            log.Fatal(err)
    }
    defer session.Close()
    c := session.DB("main").C("job")

    var results []JOB
    e := c.Find(bson.M{"v": "sign"}).All(&results)
    if e != nil {
        log.Fatal(e)
    }
    for _, job := range results[:5] {
        fmt.Println(job.ID, job.Key, job.Svc, job.DocType, job.Status, job.CreationDate)

    }

}

这是我运行程序时的输出:

ObjectIdHex("5acf91e0269c650001a82683")  sign a ok 2018-04-12 19:05:36.294 +0200 CEST
ObjectIdHex("5ad0873b169ade0001345d34")  sign a init 2018-04-13 12:32:27.14 +0200 CEST
ObjectIdHex("5ad0873e169ade0001345d36")  sign a init 2018-04-13 12:32:30.852 +0200 CEST
ObjectIdHex("5ad08742169ade0001345d38")  sign a init 2018-04-13 12:32:34.478 +0200 CEST
ObjectIdHex("5ad087492e083b00013a862a")  sign a init 2018-04-13 12:32:41.577 +0200 CEST

问题

job.Key(MongoDB文档中的j字段是一个uuid)仍为空。我也试过"github.com/satori/go.uuid",但我无法弄清楚。

所以我想知道如何处理这个uuid字段,更一般地说如何调试这个问题。 Go中的新手。

例如在python中,我可以获取一个Document并使用doc._data我可以看到该文档的所有字段,是否有相同的方法在Go中执行此操作?

更新

我尝试将Key设置为bson.Raw,我看到一些字节,但无法将它们转换为uuid:

fmt.Println(job.Key)
u := uuid.FromBytesOrNil(job.Key.Data)
fmt.Println(u)

输出:

{5 [16 0 0 0 3 160 227 5 16 134 43 72 148 138 100 29 124 251 85 53 82]}
00000000-0000-0000-0000-000000000000

3 个答案:

答案 0 :(得分:3)

使用你提到的satori/go.uuid lib,你可以通过实现这个来实现 用于UUID字段的类型的bson.Setter接口。

type Setter interface {
    SetBSON(raw Raw) error
}

最小的示例可能如下所示。首先我定义了我的结构,但是不是来自satori / go.uuid的UUID类型,而是将该类型嵌入到我自己的类型中。这允许我们在其上定义一个方法。您也可以使用type MyUUID uuid.UUID之类的不同类型声明来完成此操作,但是您需要执行类型转换uuid.UUID(record.UUID)才能访问基础uuid.UUID类型的字段和方法。< / p>

// MyUUID is a struct embedding the actual real UUID type
// so that we can implement bson.Setter
type MyUUID struct{ uuid.UUID }

// Record is a simplified version of what you're reading in
type Record struct {
    ID   int
    Name string
    UUID MyUUID `bson:"j"`
}

接下来,我们在bson.Setter

上实施MyUUID方法
// SetBSON lets us perform custom deserialization
func (m *MyUUID) SetBSON(raw bson.Raw) error {
    // First we decode the BSON data as a anonymous J struct
    var j struct {
        UUID string `bson:"$uuid"`
    }
    err := raw.Unmarshal(&j)
    if err != nil {
        return err
    }

    // Then we use the parse the string UUID
    uu, err := uuid.FromString(j.UUID)
    if err != nil {
        return err
    }

    // Finally build the result type and set it into the pointer to our record's field.
    *m = MyUUID{uu}

    return nil
}

由于缺少软件包,它不会在游乐场上运行,但可以使用完整功能的源代码来证明这一点here。我在本地运行它时的示例输出:

> go run main.go
2018/06/16 14:49:49 {1 George {fdcfa79c-6b83-444e-9a91-a02f0aeaa260}}
2018/06/16 14:49:49 {1 George fdcfa79c-6b83-444e-9a91-a02f0aeaa260}

答案 1 :(得分:2)

感谢@Thomas我已经发现我正在使用0x05种类获取bin数据。

所以我将Job struct更改为:

Key             bson.Binary         `bson:"j"`

在查询之后,我解组了这样的二进制数据:

import "github.com/satori/go.uuid"

var Ids []uuid.UUID

for _, job := range results {
    u, err := uuid.FromBytes(job.Key.Data)
    if err != nil {
        panic(err)
    }
    Ids = append(Ids, u)
}

现在在Job.Key.Data我根据this文档提供了UUID的二进制版本。

答案 2 :(得分:2)

我阅读了@sheshkovsky和@Thomas的想法,实际上我想到了一种复制粘贴解决方案,该解决方案对我来说很有效。

// MongoUUID represents a UUID as saved in MongoDB
type MongoUUID struct{ uuid.UUID }

// SetBSON implements the bson.Setter interface
func (id *MongoUUID) SetBSON(raw bson.Raw) error {
    // First we decode the BSON data as a UUID Binary
    // Optionally we can check here if the Kind is correct
    var j bson.Binary
    err := raw.Unmarshal(&j)
    if err != nil {
        return err
    }

    // Then we use the parse the string UUID
    uu, err := uuid.FromBytes(j.Data)
    if err != nil {
        return err
    }

    // Finally build the result type and set it into the pointer to our record's field.
    *id = MongoUUID{uu}

    return nil
}

// GetBSON implements the bson.Getter interface
func (id *MongoUUID) GetBSON() (interface{}, error) {
    // we create an empty UUID Binary Mongo Object
    ret := bson.Binary{
        Kind: bson.BinaryUUID,
        Data: nil,
    }

    // And we pass the UUID data to it
    if id == nil {
        ret.Data = uuid.Nil.Bytes()
    } else {
        ret.Data = id.Bytes()
    }

    // finally we return ;)
    return ret, nil
}

通过这种解决方案,您可以直接传递一个包裹uuid.UUID值的MongoUUID,就像一个超级字符:)