Mongo marshal nested documents from struct with json annotation - mongodb

Following structs define the documents I want to store in a MongoDB collection (called parents):
type Parent struct {
ID primitive.ObjectID `bson:"_id"`
Children []Child `bson:"children"`
}
type Child struct {
Field1 string `bson:"field1"`
}
I get objects of following type from an external package my project depends on:
type LibParent struct {
Children []*LibChild `json:"children"`
}
type LibChild struct {
Field1 string `json:"field1"`
}
To insert a document in parents collection given an instance of LibParent, I can marshal the LibParent to json and then unmarshal it to Parent. Then I can use the parent instance in a call to InsertOne.
The above example types simplify the actual types. The actual types have a ton of fields.
Is there a cleaner or more performant way to accomplish this i.e. insert a document into the parents collection given a LibParent object? Thanks!

If the structures are identical, you can do:
type LibParent struct {
ID primitive.ObjectID `json:"-" bson:"_id"`
Children []Child `json:"children" bson:"children"`
}
type LibChild struct {
Field1 string `json:"field1" bson:"field1"`
}
Alternatively, if the structure fields are identical, you can:
var c Child
c=*(*Child)(&libChild)
here, libChild is an instance of LibChild with json tags, and c is a Child with bson tags. You can iterate through the children array and convert using this.

Related

Go, Mongo problems

I am new using Go, but I would like to know if there is a problem if I add new attributes to a Collection in Mongo, once my model is defined in Go. Form example
I defined in Go this Model:
type material struct {
ID string `bson:"_id" json:"_id"`
Name string `bson:"name" json:"name"`
Entity string `bson:"entity" json:"entity"`
}
and I create new attributes on Material Collection for example:
Collection Material
All Attributes: ID, Name, Entity,Country(NEW ONE)
Is it necessary to update the model knowing that I will not use that attribute for the project?

How to create a table with slices in columns

I have a model that looks like this:
type Inventory struct {
gorm.Model
LocationID string
Items []Item //this is a slice of structs
Categories []Category //this is a slice of structs
}
When I create a table for it using gorm, I don't have the columns for Items or Categories.
What am i missing?
Since arrays are not supported column types in SQL—most versions of SQL at least—gorm will not create columns for fields of type slice.
You can, however, create the relationship structure you are after using an association. In this case either the has-many or many-to-many would be appropriate (I can't tell from this example, though likely has-many).
These work by creating separate tables for these nested objects. In the has-many relationship, a separate table for items and categories would be created, each with a foreign key reference to the inventory table. The many-to-many case is similar but uses a join table rather than a simple foreign key.
For example (with has-many):
type Inventory struct {
gorm.Model
LocationID string
Items []Item //this is a slice of structs
Categories []Category //this is a slice of structs
}
type Item struct {
// ...
InventoryId uint
}
type Category struct {
// ...
InventoryId uint
}
db.Model(&inventory).Related(&items)
db.Model(&inventory).Related(&categories)

Nested documents in model struct

Say I have a UserModel like so:
type (
OrderModel struct {
ID bson.ObjectId `json:"id" bson:"_id"`
...
}
UserModel struct {
...
// What do I store here? Is this an array of strings? An array of bson.ObjectID? Or an Array of OrderModel?
Orders []string `json:"orders" bson:"orders"`
Orders []bson.ObjectId `json:"orders" bson:"orders"`
Orders []OrderModel `json:"orders" bson:"orders"`
...
}
)
func (user *UserModel) PopulateOrders() {
orders := []OrderModel{}
// Query orders and assign to variable orders to then be assigned the the user Object
// {magic query here}
user.Orders = orders
}
In MongoDB, an array of ObjectIDs would be stored to reference the OrderModel documents. Later on, I have a function that will populate the Order documents like described above: PopulateOrders.
What is the best way for the case above?
I would use 2 separate fields, one for the slice of IDs, and one for the slice of lazily loaded objects.
Omit the lazily loaded object slice from saving. It could look like this:
type UserModel struct {
// ...
OrderIDs []bson.ObjectId `json:"orderIDs" bson:"orderIDs"`
Orders []OrderModel `json:"orders" bson:"-"`
// ...
}
Note that I intentionally did not exclude Orders from JSON serialization, as it is (may) be useful in JSON representation.

Golang revel+mgo - no data returned when struct variables having lowercase names

This is my struct type
type Category struct {
Name string `bson:"listName"`
Slug string `bson:"slug"`
}
used with the following function to return all results from a mongo collection -
func GetCategories(s *mgo.Session) []Category {
var results []Category
Collection(s).Find(bson.M{}).All(&results)
return results
}
The problem is that the field names in my db have names starting in lowercase but the Golang struct returns null when I try to use variable names starting with lower case. For e.g. this returns a JSON with corresponding fields empty -
type Category struct {
listName string `bson:"listName"`
slug string `bson:"slug"`
}
I'm actually porting a Meteor based API to Golang and a lot of products currently using the API rely on those field names like they are in the db!
Is there a workaround?
You need to make your fields visible for mgos bson Unmarshall by naming them with a starting capital letter. You also need to map to the appropiates json/bson field names
type Category struct {
ListName string `json:"listName" bson:"listName"`
Slug string `json:"slug" bson:"slug"`
}

Matching structure to mgo result

I have the following document in my local mongodb:
_id 25dd9d29-efd5-4b4e-8af0-360c49fdba31
name Reykjavik
initialDiseaseColouring blue
In my code I set up a city structure as the following:
type City struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string
InitialDiseaseColouring string
}
I'm querying it using
result := City{}
collection.Find(bson.M{"name":"Reykjavik"}).One(&result)
When I try to access the initialDiseaseColouring attribute it's not there
This is result when I print it:
{ObjectIdHex("32356464396432392d656664352d346234652d386166302d333630633439666462613331") Reykjavik }
Does anyone know why?
I was following the example on https://gist.github.com/border/3489566
By default, the bson codec uses the lowercased field name as the key. Use the field tag to specify a different key:
type City struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string
InitialDiseaseColouring string `bson:"initialDiseaseColouring"`
}
The addition of the field tag changes the key from "initialdiseasecolouring" to "initialDiseaseColouring".