Search code examples
gomgo

Unstructured MongoDB collections with mgo


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?


Solution

  • 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"`
    }