2013-08-20 64 views
16

我很新的去。从我在mGo的例子中看到的,为了查询一个集合然后从它读取,你必须预先定义将返回到结构中的数据。非结构化的mongoDB集合与mgo

type Person struct { 
    ID  bson.ObjectId `bson:"_id,omitempty"` 
    Name  string 
    Phone  string 
    Timestamp time.Time 
} 

在PHP中,文档被分配给一个数组。这是完美的,因为一个记录可能具有完全不同的一组键(可能不包含名称或电话,但包含电子邮件),我可以直接访问它,而不需要设置预定义的类/结构/变量。

有没有办法在Go/mGo中做同样的事情?

回答

37

有多种方式可以处理这个问题。

使用地图:

var m bson.M 
err := collection.Find(nil).One(&m) 
check(err) 
for key, value := range m { 
    fmt.Println(key, value) 
} 

注意,有没有什么特别的是关于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"` 
} 
+0

嗨古斯塔沃,谢谢你的详细解答。我不知道处理可选属性的“内联”技巧。 mgo真的是一款非常棒的软件! – tux21b

+0

是否可以在Find(nil).All(&m)上执行? –

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将数据转换成一个struct你。然后,同样的代码可能为已读:

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

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

+0

感谢响应。我也提供了一个更详细的答案。请注意,地图访问中缺少类型断言。 –

+0

谢谢,我添加了缺少的类型断言。 – tux21b

+0

不客气。对于记录来说,这个特定的情况可能是一次性处理的,使用'result [“title”]。(string)',但是你的代码和解释更具启发性。 –