Nested documents in model struct - mongodb

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.

Related

Mongo marshal nested documents from struct with json annotation

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.

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)

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

Inserting arrays of Object IDs in mgo

So recently I've been trying to insert different types of data into structures using mgo, and I've ran into a bit of a snag. When trying to insert an array of object IDs, I can't seem to figure out that format if I were to populate that object ID array within the structure.
Here's the structure as follows
type Group struct {
ID bson.ObjectId `json:"id" bson:"_id"`
GroupName string `json:"groupName"`
UserIDs []*bson.ObjectId `json:"users" bson:"userid"`
Expected []*int `json:"expected"`
Actual []*int `json:"actual"`
}
And the operation I am trying to run is to insert a new "test" table with a single userID into UserIDs.
array := []*bson.ObjectId{&findJ.ID}
c = Session.DB("test").C("Group")
err = c.Insert(&Group{GroupName: "test", UserIDs: array})
ThisPanic(err)
Where findJ has it's own ID from a separate structure. What am I doing wrong here, as it is causing a panic on inserting the array.

MongoDB and NoRM - Querying collection against a list of parameters

I need to query a collection based on a list of parameters.
For example my model is:
public class Product
{
string id{get;set;}
string title{get;set;}
List<string> tags{get;set;}
DateTime createDate{get;set;}
DbReference<User> owner{get;set;}
}
public class User
{
string id{get;set;}
...other properties...
}
I need to query for all products owned by specified users and sorted by creationDate.
For example:
GetProducts(List<string> ownerIDs)
{
//query
}
I need to do it in one query if possible not inside foreach. I can change my model if needed
It sounds like you are looking for the $in identifier. You could query products like so:
db.product.find({owner.$id: {$in: [ownerId1, ownerId2, ownerId3] }}).sort({createDate:1});
Just replace that javascript array [ownerId1, ...] with your own array of owners.
As a note: I would guess this query is not very efficient. I haven't had much luck with DBRefs in MongoDB, which essentially adds relations to a non-relational database. I would suggest simply storing the ownerID directly in the product object and querying based on that.
The solution using LINQ is making an array of user IDs and then do .Contains on them like that:
List<string> users = new List<string>();
foreach (User item in ProductUsers)
users .Add(item.id);
return MongoSession.Select<Product>(p => users .Contains(p.owner.id))
.OrderByDescending(p => p.createDate)
.ToList();