How to create a table with slices in columns - postgresql

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)

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.

Get association objects with order from JoinTable using GORM

I have two models
type Holder struct {
OwnModel
Title string `json:"title"`
Exercises []Exercise `json:"exercises" gorm:"many2many:holder_exercises_new;"`
}
type Exercise struct {
OwnModel
Title string `json:"title"`
}
And join table
type HolderExercisesNew struct {
OwnModel
HolderID int64 `json:"holder_id"`
ExerciseID int64 `json:"exercise_id"`
Order int64 `json:"order"` // my custom param for ordering
}
I want to preload Exercises to Holders but ordered by "Order" param in join table.
For example i have
holders := []models.Holder{}
database.Preload("Exercises").Find(&holders)
It gives me holders with embedded exercises but in random order.
Is there a way to get Exercises in order set in join table?
I tried what seemed obvious to me, which is using Custom Preloading SQL:
holders := []models.Holder{}
database.
Preload("Exercises", func(tx *gorm.DB) *gorm.DB {
return tx.Order("holder_exercises_new.order ASC")
}).
Find(&holders)
But that didn't work because GORM separates the loading into two queries, one of the join table and another of the joined table. A workaround I found would be, sans error checking:
holders := []models.Holder{}
database.Find(&holders)
for i := range holders {
database.
Model(&holders[i]).
Order("holder_exercises_new.order ASC").
Association("Exercises").
Find(&holders[i].Exercises)
}

GORM doesn't create ForeignKey column

I'm trying to setup relation between two models on PostgreSQL database using Go and gorm.
Here is my code, first model:
Trip.go
package model
import "github.com/jinzhu/gorm"
// Trip models
type Trip struct {
gorm.Model
TripName string
TripDescription string
}
Second model:
TripKeyPoints.go
package model
import "github.com/jinzhu/gorm"
// TripKeyPoint models
type TripKeyPoint struct {
gorm.Model
KPName string
KPDescription string
TripID Trip
}
Part of code from a file which runs migrations and initializes all
db.DropTableIfExists(&User{}, &model.Trip{}, &model.TripKeyPoint{})
db.AutoMigrate(&User{}, &model.Trip{}, &model.TripKeyPoint{})
db.Model(&model.TripKeyPoint{}).AddForeignKey("trip_id", "trips(id)", "CASCADE", "CASCADE")
Users models is just an addon but I leave it in this snippet.
Due to many tests, I drop tables at the beginning.
Here is what I receive when i run the code:
?[35m(C:/golang_lab/golang-gorm-tutorial/users.go:36)?[0m
?[33m[2019-09-21 18:40:34]?[0m ?[31;1m pq: column "trip_id" referenced in foreign key constraint does not exist ?[0m
And yeah that's true, when I log into postgres in table trip_key_points there isn't column with a foreign key.
What I need to do, I want to have one TRIP object and then assign other TripKeyPoints.
Any idea what why? Or how can I force GORM to create this column?
I explicitly define foreign key column:
// TripKeyPoint models
type TripKeyPoint struct {
gorm.Model
KPName string
KPDescription string
TripID uint `gorm:"TYPE:integer REFERENCES trips"`
}
try to edit your struct like this :
// TripKeyPoint models
type TripKeyPoint struct {
gorm.Model
KPName string
KPDescription string
TripID Trip `gorm:"foreignkey:TripId"`
}

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.

Fetch only key value from EF association

I've set up a many-to-many association between two tables based on a third table that just holds a pair of key values. Now I'd like to do a query that groups the right tables key values by the lefts without needing other data.
LeftTable { LeftID, LeftField1, LeftField2 }
JoinTable { LeftID, RightID}
RightTable { RightID, RightField1, RightField2 }
Is there any way to essentially just query the JoinTable and get all the 'RightIDs' grouped by the 'LeftIDs' without the SQL trying to fetch the fields from either side?
The JoinTable is not an entity in its own right in the model, but is mapped to the association.
I've experimented a bit with both using ObjectQuery and EntityCommand (ESQL) and both seem to still load in the other fields by joining to RightTable which I don't need.
My ESQL looks something like:
SELECT lt.LeftID, (SELECT rt.RightID
FROM NAVIGATE(lt, MyModel.LeftToRightAssoc, RightTable) as rt)
FROM MyEntities.LeftTable as lt;
but the generated SQL is still fetching in RightField1 and RightField2.
Surely there must be a simpler way to do this?
Assuming that your class Left has a navigation property Rights (a collection of Right entities) you could try this:
var list = context.Lefts.Select(l => new
{
LeftId = l.LeftId,
RightIds = l.Rights.Select(r => r.RightId)
});
foreach (var item in list)
{
Console.WriteLine("LeftId = {0}", item.LeftId);
foreach (var rightId in item.RightIds)
{
Console.WriteLine("RightId = {0}", rightId);
}
}
You would get a collection of anonymous type objects where each element has the LeftId and a collection of corresponding RightIds. This query should not touch the other fields like RightField1, etc. Instead of an anonymous type you could also create your own custom type and then project into this type in the query above.