使用mgo的非结构化MongoDB集合

使用mgo的非结构化MongoDB集合,go,mgo,Go,Mgo,我是新来的。从我在mGo示例中看到的情况来看,为了查询一个集合并从中读取,必须预定义将返回到结构中的数据 type Person struct { ID bson.ObjectId `bson:"_id,omitempty"` Name string Phone string Timestamp time.Time } 在PHP中,文档被分配给一个数组。这非常完美,因为一个记录可能有完全不同的密钥集(可能不包含姓名或电话,但包含电

我是新来的。从我在mGo示例中看到的情况来看,为了查询一个集合并从中读取,必须预定义将返回到结构中的数据

type Person struct {
    ID        bson.ObjectId `bson:"_id,omitempty"`
    Name      string
    Phone     string
    Timestamp time.Time
}
在PHP中,文档被分配给一个数组。这非常完美,因为一个记录可能有完全不同的密钥集(可能不包含姓名或电话,但包含电子邮件),我可以直接访问它,而无需设置预定义的类/结构/变量


在Go/mGo中是否有同样的方法?

您可以将所有内容存储在地图中。
mgo/bson
包提供了一种可用于存储任意数据的
bson.M
数据类型,由于MongoDB不强制实施强模式,
mgo
在内部为所有内容使用
bson.M
类型

如果您只想显示数据,使用<代码> BSON.M./Cord>应该很好,但是一旦您想开始使用它,就应该考虑使用Stutt。否则,您的程序中将需要大量类型断言。例如,您想在大写中打印您的文档的标题(<代码>结果[标题] ] /代码>。只要使用

bson.M
,您的代码就会如下所示:

// is there a title attribute?
if title, ok := result["title"]; ok {
    // is it a string? (and not another map or integer or something else)
    if titleStr, ok := title.(string); ok {
        // ok, it is a string
        fmt.Println("Title: ", strings.ToUpper(titleStr))
    }
}
当您让
mgo
为您将数据转换为结构时,您的程序将变得更可读、更易于维护。然后,相同的代码可能会读为:

fmt.Println(strings.ToUpper(result.Title))

通常,您为要处理的每种类型的文档定义一种结构类型(即一种类型用于“用户”,另一种类型用于“博客文章”,等等),其中包含您可能要访问的每个属性。如果您的用户文档没有指定电子邮件地址,则在解码时,您只会得到一个空字符串(或者更一般地说,是零值)。

有多种方法可以处理此问题

使用地图:

var m bson.M
err := collection.Find(nil).One(&m)
check(err)
for key, value := range m {
    fmt.Println(key, value)
}
请注意,就mgo而言,没有什么特别之处。它只是一个
map[string]接口{}
类型,您可以定义自己的映射类型并将其与mgo一起使用,即使它们具有不同的值类型

使用文档切片:

var m bson.M
err := collection.Find(nil).One(&m)
check(err)
for key, value := range m {
    fmt.Println(key, value)
}
是mgo内部已知的一个切片,它的存在既是为了提供更有效的机制,也是为了提供一种保存密钥顺序的方法,MongoDB在某些情况下(例如,在定义索引时)使用这种方法

例如:

var d bson.D
err := collection.Find(nil).One(&d)
check(err)
for i, elem := range d {
    fmt.Println(elem.Name, elem.Value)
}
type Person struct {
    ID        bson.ObjectId `bson:"_id,omitempty"`
    Name      string
    Phone     string
    Extra     bson.M `bson:",inline"`
}
使用内联地图字段

,inline
bson也可以在地图字段中使用,这样你就可以吃蛋糕了。换句话说,它支持使用结构,以便方便地操作已知字段,同时允许通过内联映射处理未知字段

例如:

var d bson.D
err := collection.Find(nil).One(&d)
check(err)
for i, elem := range d {
    fmt.Println(elem.Name, elem.Value)
}
type Person struct {
    ID        bson.ObjectId `bson:"_id,omitempty"`
    Name      string
    Phone     string
    Extra     bson.M `bson:",inline"`
}

谢谢你的回复。我也提供了一个更详细的答案。请注意,映射访问中缺少类型断言。谢谢,我添加了缺少的类型断言。不客气。为了记录在案,这个特定的案例可能是一次处理的,结果是
结果[“title”]。(字符串)
,但是您的代码和解释更具指导意义。您好Gustavo,谢谢您的详细回答。我还不知道处理可选属性的“内联”技巧。mgo真是一款很棒的软件!是否可以在Find(nil).All(&m)上执行?是的,只需使用
var ms[]bson.m
@JamesSapamyou可以使用类型
接口{}