I have two structs that represent models that will be inserted into a mongodb database. One struct (Investment) has the other struct (Group) as one of its fields.
type Group struct { Base Name string `json:"name" bson"name"` } type Investment struct { Base Symbol string `json:"symbol" bson:"symbol" binding:"required"` Group Group `json:"group" bson:"group"` Fields bson.M `json:"fields" bson:"fields"` }
The problem I'm having is that in the Investment model, Group is not required. If there is no group, I think its better for it to not be inserted in the db. Whats the best way to handle a db model such as this in Go?
In general the best advice is to make use of the zero value. Create structures so that zero values of false are useful, rather than a pain. This is not always possible, so changing the types of the fields in the Foo struct to be pointers will allow you to check the 3 cases you are after.
An empty structIt occupies zero bytes of storage. As the empty struct consumes zero bytes, it follows that it needs no padding. Thus a struct comprised of empty structs also consumes no storage.
— A structure or union is defined without any named members (including those specified indirectly via anonymous structures and unions) (6.7.
An empty struct is a struct type without fields struct{} . The cool thing about an empty structure is that it occupies zero bytes of storage. You can find an accurate description about the actual mechanism inside the golang compiler in this post by Dave Chaney.
tl;dr: Use ,omitempty
, and if you need to worry about the difference between a zero value and null/not specified, do what the GitHub API does and use a pointer.
Both json
and bson
support the ,omitempty
tag. For json, "empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero" (json docs). For bson, ,omitempty
means "Only include the field if it's not set to the zero value for the type or to empty slices or maps", and zero values include empty strings and nil pointers (bson docs).
So if you really need a Group struct, you can put a *Group
in instead, and it won't be stored when the pointer is nil. If Investment
only needs to hold the group's name, it's even simpler: ""
as group name keeps a group key from being stored.
bson
defaults to using the lowercased field name already so you can omit that from the struct tag when they match. json
will default to the Capitalized name, so specify the lowercase name in a tag if you need lowercase.
So, best case, maybe you can just use:
type Investment struct { Base Symbol string `json:"symbol" binding:"required"` Group string `json:"group,omitempty" bson:",omitempty"` Fields bson.M `json:"fields"` }
If you ever run into fields where the zero value for the type ("", 0, false, etc.) is distinct from "not specified", you can do what the GitHub API does and put pointers in your structures--essentially an extension of the *Group
trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With