Unstructured MongoDB collections with mgo

kwolfe picture kwolfe · Aug 20, 2013 · Viewed 11.9k times · Source

I'm VERY new to Go. From what I've seen in the examples of mGo, in order to query a collection and then read from it, you have to predefine the data that will be coming back in a struct.

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

In PHP, the document was assigned to an array. This was perfect as one record may have completely different set of keys (may not contain Name or Phone but contain Email) and I could access it directly without setting up a predefined class / struct / variable.

Is there a way to do the same in Go / mGo?

Answer

Gustavo Niemeyer picture Gustavo Niemeyer · Aug 21, 2013

There are multiple ways you can handle this.

Using a map:

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

Note that there's nothing special about bson.M as far as mgo is concerned. It's just a map[string]interface{} type, and you can define your own map types and use them with mgo, even if they have a different value type.

Using a document slice:

The bson.D is a slice that is internally known to mgo, and it exists both to offer a more efficient mechanism and to offer a way to preserve the ordering of keys, which is used by MongoDB in some circumstances (for example, when defining indexes).

For example:

var d bson.D
err := collection.Find(nil).One(&d)
check(err)
for i, elem := range d {
    fmt.Println(elem.Name, elem.Value)
}

Using an ,inline map field

The ,inline bson flag can also be used in a map field, so that you can have your cake and eat it too. In other words, it enables using a struct so that manipulating known fields is convenient, and at the same time allows dealing with unknown fields via the inline map.

For example:

type Person struct {
    ID        bson.ObjectId `bson:"_id,omitempty"`
    Name      string
    Phone     string
    Extra     bson.M `bson:",inline"`
}