bli00
bli00

Reputation: 2787

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?

Upvotes: 4

Views: 3042

Answers (2)

Thundercat
Thundercat

Reputation: 120951

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.

Upvotes: 4

icza
icza

Reputation: 417612

  1. Should I avoid the BSON import?

I see no reason to do so. MongoDB (through mgo) and BSON walk hand-in-hand. It doesn't matter if you import bson or not, bson will still be used under the hood (to serialize / represent the data sent back and forth).

  1. Can I query for all matching patterns wtihout using BSON or specifying the entire interface?

Yes, you can, if you use the omitempty option when specifying the "bson" tags, like this:

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

Now if you do a query like this:

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

Then when the filter value is marshalled into BSON, it will only contain a "name" field, because Phone is its zero value, so it will not be marshaled.

Of course using omitempty may not be what you want when you do insert / update, so using a single type for representing and querying persons may not be sufficient. Generally, you should "tag" Person how you want to represent your data, and you should use simple bson.M values to query, or create another struct that models how you want to query.

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

They are not interchangeable, so if you only specify json tags, those are not used (ignored) by the bson package, and similarly, if you only specify bson tags, the encoding/json package of the standard library will not use those. They are 2 different tags, used for 2 different purposes, used by 2 different libraries (packages).

You may or may not specify both. If you never intend to serialize your data into JSON, you don't have to specify json tags.

Upvotes: 2

Related Questions