我是Go的新手。从我在mGo示例中看到的,为了查询集合然后从中读取,您必须预定义将在结构中返回的数据。
type Person struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string
Phone string
Timestamp time.Time
}
在PHP中,文档被分配给一个数组。这是完美的,因为一个记录可能有完全不同的密钥集(可能不包含名称或电话但包含电子邮件),我可以直接访问它而无需设置预定义的类/结构/变量。
有没有办法在Go / mGo中做同样的事情?
答案 0 :(得分:47)
有多种方法可以解决这个问题。
使用地图:
var m bson.M
err := collection.Find(nil).One(&m)
check(err)
for key, value := range m {
fmt.Println(key, value)
}
请注意,就mgo而言,bson.M没有什么特别之处。它只是map[string]interface{}
类型,您可以定义自己的地图类型并将其与mgo一起使用,即使它们具有不同的值类型。
使用文档切片:
bson.D是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)
}
使用内联地图字段
,inline
bson flag也可以在地图字段中使用,这样你就可以吃蛋糕了。换句话说,它允许使用结构,以便操作已知字段很方便,同时允许通过内联映射处理未知字段。
例如:
type Person struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string
Phone string
Extra bson.M `bson:",inline"`
}
答案 1 :(得分:2)
您可以将所有内容存储在地图中。 mgo/bson
包提供了可用于存储任意数据的bson.M
数据类型,并且由于MongoDB不强制执行强模式,mgo
使用bson.M
类型内心的一切。
如果您只想显示数据,使用bson.M
应该没问题,但是一旦您想开始使用它,您应该考虑使用结构。否则,您的程序中需要很多类型断言。例如,假设您要以大写形式打印文档的标题(result["title"]
)。仅使用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))
通常,您为要处理的每种类型的文档定义一种结构类型(即一种类型用于"用户"另一种用于"博客文章"等等)您可能想要访问的每个属性。如果您的用户文档没有分配电子邮件地址,则在解码时只会返回一个空字符串(或者更常见的是零值)。