I have the following Car model and a cars slice:
type Car struct {
ID int `json:"id"`
Name string `json:"title"`
}
var cars []Car
On a Postgres database, I have created a cars table to save car records.
create table cars (id serial, name varchar);
And saved, a couple of car records:
insert into cars (name) values ('Toyota');
insert into cars (name) values ('Lexus');
The records are created successfully with incremental integer ids 1 and 2.
In my Go server, I am making the following query to get the car records:
db.Query("SELECT * from cars").Rows(&cars)
for _, car := range cars {
fmt.Println(car)
}
Although there is a response, the id for each record comes as 0. I have tried to find out why, but I was not able to. Anyone has any idea?
database/sql package does not provide to scan the data directly to a struct, you should iterate over the rows returned from the database query and then scan the data into struct as:
var cars []cars
for rows.Next() {
var car cars
err = rows.Scan(&c.ID, &c.Name)
if err != nil {
log.Fatalf("Scan: %v", err)
}
cars = append(cars, car)
}
fmt.Println(cars)
Or you can use extension for sql package name sqlx which will provide you to directly scan the result into the slice of struct as:
cars := []cars{}
db.Select(&cars, "SELECT * from cars")
Related
I have two tables users and documents. They are related in such a way that each document must belong to a user using a one to many relationship. When I try updating a document I get the following error
ERROR: insert or update on table "documents" violates foreign key
constraint "fk_users_documents" (SQLSTATE 23503)
Here are my structs definition and update function
type User struct {
gorm.Model
Name string
Email string
Password string
Documents []Document
}
type Document struct {
gorm.Model
Name string
UserID uint
}
//Update document by id
func (h handler)UpdateDocument(w http.ResponseWriter, r *http.Request) {
// once again, we will need to parse the path parameters
var updatedDoc Document
reqBody, _ := ioutil.ReadAll(r.Body)
json.Unmarshal(reqBody, &updatedDoc)
var document Document
vars := mux.Vars(r)
id := vars["id"]
if result := Db.First(&updatedDoc, id); result.Error != nil {
fmt.Println(result.Error)
}
document.Name=updatedDoc.Name
Db.Save(&document)
json.NewEncoder(w).Encode(&updatedDoc)
}
You are calling Db.Save(&document) but document has only its Name field populated. This means that the UserID is set to 0. I'm guessing you don't have any user with ID 0 present in the User table, therefore this violates the foreign key constraint.
The UserID field shall always be set to an existing user when updating a document otherwise the query will fail.
Regardless of this, I'd suggest you to study a bit of database and golang basics because the code you posted is quite messy.
I've been reading the GoLang go-pgsql documentation in order to figure out how to access data with nested objects, but I have so far been unsuccessful.
Here's the description of what I am trying to achieve:
I have two models ClimateQuestions and Steps:
type ClimateQuestions struct {
tableName struct{} `pg:"climatequestions"`
Id int `json:"id" pg:",pk"`
Title string `json:"title"`
Steps []*Steps `pg:"rel:has-many"`
}
type Steps struct {
tableName struct{} `pg:"steps"`
Id int `json:"id"`
Label string `json:"label"`
Number int `json:"number"`
QuestionId int `json:"question_id"`
}
and here is how they're defined in the database:
CREATE TABLE climatequestions (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL
);
CREATE TABLE steps (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
value DOUBLE PRECISION NOT NULL,
question_id INT REFERENCES climatequestions(id)
);
And a relationship between these models is this: For every climate question, there can be many steps. I have denoted this by adding a field in ClimateQuestions struct called Steps with rel:has-many.
Now, from the database, I would like to obtain all the climate questions, and within each of them, I want an array of steps data.
My first method to achieve this has been the following:
var climateQuestions []model.ClimateQuestions
err := db.Model(&climateQuestions).Select()
This partially works in that it returns all the data relevant for climate questions, but it does not add the nested steps data. Here is the JSON format of what is returned:
[{"id":1,"title":"first question?","Steps":null},{"id":2,"title":"second question?","Steps":null}]
Any ideas as to how I may achieve this?
Because you have custom join foreign key, you need to add tag pg:"rel:has-many,join_fk:question_id" in ClimateQuestions.Steps
In struct Steps, you need to tell pg which field it is.
You forgot to call Relation function
this is the correct struct
type ClimateQuestions struct {
tableName struct{} `pg:"climatequestions"`
Id int `json:"id" pg:",pk"`
Title string `json:"title"`
Steps []*Steps `pg:"rel:has-many,join_fk:question_id"`
}
type Steps struct {
tableName struct{} `pg:"steps"`
Id int `json:"id"`
Label string `json:"label" pg:"title"`
Number int `json:"number" pg:"value"`
QuestionId int `json:"question_id"`
}
this is how you should exec db.
var climateQuestions []ClimateQuestions
err := db.Model(&climateQuestions).Relation("Steps").Select()
if err != nil {
panic(err.Error())
}
for _, v := range climateQuestions {
fmt.Printf("%#v\n", v)
for _, v1 := range v.Steps {
fmt.Printf("%#v\n", v1)
}
fmt.Println("")
}
I have a product-image (1:M) relation and basically i want to map those images to a slice in my struct. I am using sqlx library to make it bit easier.
I searched for a while and maybe the best answer was in this thread: Efficiently mapping one-to-many many-to-many database to struct in Golang.
The answer with creating the view and returning everything as a json works but it feels somehow hacky.
Ideally what i want to do is use postgres json_agg to return the json array inside the images column that would match my type so i could scan into it.
I did this with nodejs several times but here i don't know how. Do i need to implement custom Scan and Value methods or is there a simpler way. I didn't show this but i also have a category that is 1:1 and i can embed that category in product and do a left join and it works with sqlx, but not with images type.
Simplified models
type Image struct {
ID int,
URL string,
ProductID int
}
type ImageList []*Image
type Product struct {
ID int `db:"id"`
Name string `db:"name"`
Images ImageList `db:"images"`
}
DB Tables
create table product (
id int generated always as identity primary key,
name varchar(255),
);
create table product_image (
id int generated always as identity primary key,
url text not null,
product_id int references product(id)
);
I am trying something like this now:
q := `SELECT
p.*,
COALESCE(JSON_AGG(img.*) FILTER (WHERE img.product_id IS NOT NULL), '[]'::json) AS images
FROM product p
LEFT JOIN product_image img ON p.id = img.product_id
WHERE p.id = 1
GROUP BY p.id`
var p Product
if err := sqlxdb.Get(&p, q); err != nil {
fmt.Printf("Error: %v\n", err)
}
I get this error:
sql: Scan error on column index 26, name "images": unsupported Scan, storing driver.Value type []uint8 into type *model.ImageList
This seems like a super common scenario and yet i can't find any examples...
Or finally am i even stupid for doing this because i can just do forEach in JS and do like 50 queries to fetch all the images for every product.
One solution for getting list of items could be done using this mapping lib: carta
q := `SELECT p.*, img.id AS img_id, img.url AS img_url
FROM public.product p
LEFT JOIN product_image img ON p.id = img.product_id`
rows, err := sqlxdb.Query(q)
if err != nil {
fmt.Println(err)
}
var products []*model.Product
carta.Map(rows, &products)
And for the img struct i would use db:"img_id" prefix and so on, because i select with alias...
I have some code to create the table in Postgres DB
import (
"github.com/jinzhu/gorm"
_ "github.com/lib/pq"
)
type Table struct {
Id int `gorm:"primary_key"`
Name string `gorm:"type:varchar(100)"`
Addr string `gorm:"type:varchar(100)"`
}
func main() {
db, _ := gorm.Open("postgres", "user=postgres password=poilo777 dbname=mydb sslmode=disable")
defer db.Close()
db.CreateTable(&Table{})
user := &Table{Name: "ololo", Addr: "pololo"}
there are 2 problems, i faced:
1) in database created a table "tables" instead of "Table"
2) how can I insert data in existing another tables? (for example "users")
1) You can set Table's table name to be table
func (Table) TableName() string {
return "table"
}
Another way is to set singularTable true, then Table's default table name will be table instead of tables. But it will affect all tables the same.
set db.SingularTable(true)
2) In ORM you should define your table object. Here is a struct called Table. Gorm will create a new table called tables in database unless you want to overwrite table's name you can follow step 1.
By default, the golang Postgres Client will implicitly use the pluralized version of your struct name[1]. For example
type Student struct {
FirstName string
LastName string
}
// will create a table name `students`
You can override it like the following, depending on what you are using
GORM
// Set User's table name to be `profiles`
func (Student) TableName() string {
return "college_students"
}
GO-PQ
type Student struct {
tableName struct{} `pg:"college_students,alias:g"``
}
https://gorm.io/docs/conventions.html#Pluralized-Table-Name
My solving of this problem:
db.Table("my_table").CreateTable(&Table{})
user := &Table{Name: "ololo", Addr: "pololo"}
db.Table("my_table").Create(user)
This code creates table my_table as I wanted
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.