Search code examples
mongodbgostructmongodb-querymgo

MongoDB in Go in relation to JSON and BSON


I'm learning how to use the community maintained mgo repo linked here.

I've discovered through this example that the way to query for some pieces of data seems to be done through BSON (The community maintained version of the BSON library is linked here):

type Person struct {
    Name      string
    Phone     string
}

c.Find(bson.M{"name": "Alice"}).All(&result)

Which will give me all Person with name Alice.

I have also discovered that I don't need BSON to do this query. Find() takes any interface:

c.Find(Person{
    Name: "Alice",
    Phone: "1234",
}).All(&result)

Will also work, but only returning the specified exact query. If I leave out piece of the struct like this:

c.Find(Person{
    Name: "Alice",
}).All(&result)

result will be empty.


It seems to me that avoiding BSON is more intuitive and simpler. So my questions are:

  1. Should I avoid the BSON import?
  2. Can I query for all matching patterns without using BSON or specifying the entire interface?
  3. Should I specify BOTH JSON and BSON keys like in json:"name" or are they interchangeable?

Solution

  • The mgo/bson package is used to encode and decode all database commands and results, even when the application does not use the package directly.

    The composite literal Person{ Name: "Alice" } returns a Person value with the Phone field set to "". The BSON encoder encodes this value to what is logically the value {"Name": "Alice", "Phone": ""}. A query with this value returns all documents with Name equal "Alice" AND Phone equal to "". Apparently there are no documents that match this query in the collection.

    The query document must have a Name field only to query all documents with Name equal "Alice" and Phone with any value or not set at all.

    Should I avoid the BSON import?

    No, use the bson package directly when it's helpful.

    Can I query for all matching patterns without using BSON or specifying the entire interface?

    The bson.M type is usually the best way to construct queries, but you can do it without it. For example, you can query for all documents with name "Alice" like this:

    c.Find(struct { Name string }{Name: "Alice"}).All(&result)
    

    You can also use map[string]interface{}:

    c.Find(map[string]interface{}{"Name": "Alice"}).All(&result)
    

    Finally, you can use the BSON encoder's "omitempty" feature to omit empty fields from the encoded value. I do not recommend this approach because it prevents you from querying for documents where the field is equal to "". Change the struct type to the following for this approach:

    type Person struct {
        Name  string `bson:",omitempty"`
        Phone string `bson:",omitempty"`
    }
    

    Should I specify BOTH JSON and BSON keys like in json:"name" or are they interchangeable?

    They are not interchangeable. Specify the tags as needed for the BSON encoder and the JSON encoder.