How to work with has many relation in gorm? - postgresql

import (
"gorm.io/gorm"
"gorm.io/driver/postgres"
)
type School struct {
gorm.Model
Students []Student `json:"students"`
}
type Student struct {
gorm.Model
Name string `json:"name"`
}
func init() {
//connect to db first
conn, err := gorm.Open(postgres.New(postgres.Config{
DSN: dbUri,
PreferSimpleProtocol: true,
}), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
db = conn
db.AutoMigrate(&Student{}, &School{})
}
Create the structs and automigrating it gives me an error. Do you know why this is? Also how to you work with has many relation in gorm, what kind of data does it create in postgres?
Error -
Need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface

You need to add a SchoolID field to your Student. See the docs here for full usage.
type Student struct {
gorm.Model
SchoolID uint
Name string `json:"name"`
}
To answer the second part, it will create two tables for you. Schools and students. The students will have a foreign key that points to the ID of a school. I would read the docs to learn how this works more.

Related

why after I created a new table using go-pg, and found that the name of the new table changed?

why after I created a new table using go-pg, and found that the name of the new table changed?
for example,the struct name is "story" and it became "stories" in pg.
type Newtb struct {
Id int64
Name string
Emails []string
}
func createTest(db *pg.DB) error {
err := db.Model((*Newtb)(nil)).CreateTable(&orm.CreateTableOptions{
IfNotExists: true,
})
if err != nil {
log.Fatal(err)
return err
}
return nil
}
enter image description here
My struct name is "Newtb" and it turned "newtbs" in postgreSQL.
Can someone explain to me why an 's' was added to the table name?
Table name and alias are automatically derived from the struct name by
underscoring it. Table name is also pluralized, for example struct
Genre gets table name genres and alias genre. You can override the
default table name and alias using tableName field:
type Genre struct {
tableName struct{} `pg:"genres,alias:g"`
}

Using an opaque ID type in place of primitive.ObjectID

In a db package, I don't want to expose MongoDB's primitive.ObjectID type as part of its public API. Instead, I want to define type Id interface{} within the db package and expose that. Since the driver doesn't know how to transform the database's ObjectID type into my custom ID type, I registered a type decoder like so:
type Id interface{}
var idType = reflect.TypeOf((*Id)(nil)).Elem()
type User struct {
Id `bson:"_id,omitempty"`
}
func main() {
reg := bson.NewRegistryBuilder().
RegisterTypeDecoder(idType, bsoncodec.ValueDecoderFunc(idDecodeValue)).
Build()
client, err := mongo.Connect(context.TODO(), options.Client().
ApplyURI("...").
SetRegistry(reg))
coll := client.Database("...").Collection("...")
var u0 User
coll.InsertOne(context.TODO(), u0)
var u1 User
coll.FindOne(context.TODO(), bson.D{}).Decode(&u1)
}
func idDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || val.Type() != idType {
return bsoncodec.ValueDecoderError{
Name: "IdDecodeValue",
Types: []reflect.Type{idType},
Received: val,
}
}
oid, _ := vr.ReadObjectID()
val.Set(reflect.ValueOf(oid))
return nil
}
I saw that there exists a bsoncodec.NewEmptyInterfaceCodec() to use in place of idDecodeValue, but that only seems to work when User.Id's type is exactly interface{}. I wrote idDecodeValue based off of the existing codecs, but I'm not entirely sure what's going on (mostly due to not knowing when val.IsValid() would ever return false). Is all of this the best, most idiomatic way to go about supporting a custom ID type?

extracting nested struct data from mongodb

Have a struct as follows
type Person struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `json:"name"`
Phone string `json:"phone"`
}
and then want to nest it in another struct
type Customer struct {
ID bson.ObjectId `bson:"_id,omitempty"`
StoreName string
Person Person `json:"persons"`
}
instantiated as
customer := Customer{bson.NewObjectId(), "Seattle", p1}
and insterted into Mongo db (I am using the mgo driver for golang)
err = databaseConnection.Insert(&customer)
How do I retrieve the customer struct from the DB using parameters from the nested Person struct? E.g. pull all Customer structs that have a Person struct named “John”
I am trying
err = databaseConnection.Find(bson.M{XXXXXXXXX}).All(&resultsB)
but I can’t figure out what XXXXXX should be.
You could try something like that: bson.M{"person.name": "john"}
check mongodb documentation on embedded documents: https://docs.mongodb.com/manual/tutorial/query-embedded-documents/

Go compile error "undefined function"

I have the following pieces of code:
Interface & function definition:
package helper
import "gopkg.in/mgo.v2/bson"
// Defines an interface for identifiable objects
type Identifiable interface {
GetIdentifier() bson.ObjectId
}
// Checks if a slice contains a given object with a given bson.ObjectId
func IsInSlice(id bson.ObjectId, objects []Identifiable) bool {
for _, single := range objects {
if single.GetIdentifier() == id {
return true
}
}
return false
}
The definition of the user struct which satisfies 'Identifiable':
package models
import (
"github.com/my/project/services"
"gopkg.in/mgo.v2/bson"
)
type User struct {
Id bson.ObjectId `json:"_id,omitempty" bson:"_id,omitempty"`
Username string `json:"username" bson:"username"`
Email string `json:"email" bson:"email"`
Password string `json:"password" bson:"password"`
Albums []bson.ObjectId `json:"albums,omitempty" bson:"albums,omitempty"`
Friends []bson.ObjectId `json:"friends,omitempty" bson:"friends,omitempty"`
}
func GetUserById(id string) (err error, user *User) {
dbConnection, dbCollection := services.GetDbConnection("users")
defer dbConnection.Close()
err = dbCollection.Find(bson.M{"_id": bson.ObjectIdHex(id)}).One(&user)
return err, user
}
func (u *User) GetIdentifier() bson.ObjectId {
return u.Id
}
A test which checks for the existence of an object inside a slice:
package controllers
import (
"github.com/my/project/helper"
"gopkg.in/mgo.v2/bson"
)
var testerId = bson.NewObjectId()
var users = []models.Users{}
/* Some code to get users from db */
if !helper.IsInSlice(testerId, users) {
t.Fatalf("User is not saved in the database")
}
When I try to compile the test it I get the error: undefined helper.IsInSlice. When I rewrite the IsInSlice method to not take []Identifiable but []models.User it works fine.
Any ideas?
Your problem is that you're trying to use a value of type []models.Users{} as a value of type []Identifiable. While models.Users implements Identifiable, Go's type system is designed so that slices of values implementing an interface cannot be used as (or converted to) slices of the interface type.
See the Go specification's section on conversions for more details.
Apparently, Go did not rebuild my package and was looking for the function in an old build. It was therefore undefined. Performing rm -fr [GO-ROOT]/pkg/github.com/my/project/models did the trick.

Golang Selecting fields from a struct array

I get an array of all the users with an attribute ID in their document:
Users := []backend.User{}
err := Collection.Find(bson.M{"channel_id": bson.ObjectIdHex(chId)}).All(&Users)
if err != nil {
println(err)
}
Which I want to send as a JSON response back to the browser/client. However, the User struct contains things like IDs and Hahsed Passwords which i don't want to send back!
I was looking at something like using the reflect package to select the fields of the struct and then putting them into a map[string]interface{} but im not sure how to do it with an array of users.
You can ignore struct fields while json.Marshal.
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Id int `json:"-"`
Name string `json:"name"`
}
type Users []*User
func main() {
user := &Users{
&User{1, "Max"},
&User{2, "Alice"},
&User{3, "Dan"},
}
json, _ := json.Marshal(user)
fmt.Println(string(json))
}
Runnable example in Play Golang: http://play.golang.org/p/AEC_TyXE3B
There is a very useful part about using the tags in the doc. Same for XML, but it's more complicated for obvious reasons.