i am trying to do a left join on query but i have an invalid reference to FROM-Clause
here are the structure of the code
this is the product table
CREATE TABLE products
(
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
title VARCHAR(255),
productdesc TEXT,
costprice DOUBLE PRECISION,
recommendprice DOUBLE PRECISION,
views BIGINT DEFAULT 0,
enabled BOOLEAN DEFAULT FALSE,
category_id BIGINT REFERENCES categories (id) ON DELETE CASCADE NOT NULL,
)
this is the category table
CREATE TABLE categories
(
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
pid BIGINT NOT NULL,
title VARCHAR(255),
image VARCHAR(255),
);
this is the type struct
type Product struct {
TableName struct{} `sql:"products"`
ID int64 `json:"id"`
TITLE string `json:"title"`
PRODUCTDESC string `json:"product_desc"`
COSTPRICE float64 `json:"costprice"`
RECOMMENDPRICE float64 `json:"recommendprice"`
VIEWS int64 `json:"views"`
ENABLED bool `json:"enabled"`
CATEGORYNAME string `json:"categoryname"`
}
type Category struct {
tableName struct{} `pg:"categories"`
ID int64 `json:"id"`
Title string `json:"title"`
Image string `json:"image"`
}
this is the actual query to database
func (t *ProductRepo) GetAllProducts() ([]*domain.Product, error) {
var products []*domain.Product
query := t.DB.Model(&products).
ColumnExpr("products.*").
ColumnExpr("c.id AS category_id, c.title AS categoryname").
Join("LEFT JOIN categories AS c ON c.id = products.category_id")
err := query.Select()
if err != nil {
return nil, err
}
return products, nil
}
this is the actual error from postman
{
"error": "ERROR #42P01 invalid reference to FROM-clause entry for table \"products\""
}
any help would be great,
thanks advance
Jason
Related
In my struct, i have the following
type Task struct {
gorm.Model
Id int `json:"id" gorm:"primaryKey;AUTO_INCREMENT"`
UserId int `json:"user_id" gorm:"Index;not null" validate:"required"`
TaskId int `json:"task_id" gorm:"Index;not null" validate:"required"`
JobId int `json:"job_id" gorm:"not null" validate:"required"`
Latitude float64 `json:"latitude" gorm:"not null" validate:"required"`
Longitude float64 `json:"longitude" gorm:"not null" validate:"required"`
StartAt time.Time `json:"start_at"`
EndAt time.Time `json:"end_at"`
CreatedAt time.Time
UpdatedAt time.Time
}
and i have this function that saves to the table with the following
{ "user_id": 1,
"location":[5748.5445, 89790.454],
"latitude": 89790.454,
"longitude": 5748.5445,
"startAt": "2030-10-30T10:58:00.000Z",
"endAt": "2031-10-30T10:58:00.000Z"
}
func CreateTask(c *fiber.Ctx) error {
var opentask models.JobOpenTask
if err := c.BodyParser(&opentask); err != nil {
return c.Status(400).JSON(err.Error())
}
db.DB.Db.Create(&opentask)
return c.Status(200).JSON("OK")
}
When this runs, it still saves the record on the DB but I expect it to throw and error when it tries to save since it is not null in my struct but why is it able to save to the Db without throwing an error?
You need to use sql.NullIntxx or int/float pointer for this because default/empty values of int/float is 0, which is not null for database.
So gorm and DB will allow this to pass through as non null value.
Similarly for string type where one has to use *string or sql.NullStting as default value of string is "" (blank string) and not nil.
First you should check that migrations have been run properly that means not null constraint for user_id, task_id, job_id, .. columns are created in database.
Secondly you have to use pointer because golang has a concept of zero value that means int, float, string, bool have default values of 0, 0.0, "", false accordingly, if you doesn't assign any value. But if you use pointer then this fields will be nil and eventually NULL will be sent in db. And if there is a NOT NULL constraint for that column error will occur.
null just apply for pointer
gorm.Model include
type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt DeletedAt `gorm:"index"`
}
you don't need declare Id, CreatedAt, UpdatedAt in your struct
Correct your struct as bellow:
type Task struct {
gorm.Model
UserId int `json:"user_id"`
TaskId int `json:"task_id"`
JobId int `json:"job_id"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
StartAt time.Time `json:"start_at"`
EndAt time.Time `json:"end_at"`
}
And tag and best practice is control by database with column defined not null constraint
AUTO_INCREMENT should be create on the database when your create table , this need control by database , not by language
declare table as bellow:
create table tasks (
int primary key AUTO_INCREMENT,
user_id int not null,
task_id int not null,
job_id int not null,
latitude int not null,
longitude int not null,
start_at datetime,
created_at datetime,
updated_at datetime
)
wish your study well!
When I try to update the Shoppinglist struct with the data I get an "there is no unique or exclusion constraint matching the ON CONFLICT specification (SQLSTATE 42P10)" Error
These are my Structs
type Shoppinglist struct {
Model
ID int `gorm:"primaryKey" json:"id"`
Title string `json:"title"`
Items []Item `json:"items" gorm:"foreignKey:ParentListID;references:ID;"`
Owner string `json:"owner"`
Participants pq.StringArray `gorm:"type:text[]" json:"participants"`
}
type Item struct {
Model
ParentListID int `gorm:"primaryKey" json:"parentListId"`
Title string `json:"title"`
Position int `json:"position"`
Bought bool `json:"bought"`
}
And this is the Code I execute when trying to edit a list
func EditList(id int, data map[string]interface{}) error {
//https://github.com/go-gorm/gorm/issues/3487
shoppinglist := Shoppinglist{
ID: data["id"].(int),
Title: data["title"].(string),
Items: data["items"].([]Item),
Owner: data["owner"].(string),
Participants: data["participants"].([]string),
}
if err := db.Session(&gorm.Session{FullSaveAssociations: true}).Where("id = ?", id).Updates(&shoppinglist).Error; err != nil {
return err
}
return nil
}
This is where I execute the EditList and where I set all the values to pass nito the map:
type Shoppinglist struct {
ID int
Title string
Items []models.Item
Owner string
Participants []string
PageNum int
PageSize int
}
func (s *Shoppinglist) Edit() error {
shoppinglist := map[string]interface{}{
"id": s.ID,
"title": s.Title,
"items": s.Items,
"owner": s.Owner,
"participants": s.Participants,
}
return models.EditList(s.ID, shoppinglist)
}
Before I was just using a []string instead of []Item and that was working perfectly. Now everything updates except for the []Item
These are the SQL Queries executed:
UPDATE "shoppinglists" SET "modified_on"=1628251977096,"title"='kjhdsfgnb',"owner"='janburzinski1#gmail.com',"participants"='{}' WHERE id = 517687 AND "id" = 517687
INSERT INTO "items" ("created_on","modified_on","deleted_at","title","position","bought","parent_list_id") VALUES (1628251977,1628251977116,NULL,'dfkjhgndfjkg',1,false,517687),(1628251977,1628251977116,NULL,'dfgh123',2,true,517687) ON CONFLICT ("parent_list_id") DO UPDATE SET "created_on"="excluded"."created_on","modified_on"="excluded"."modified_on","deleted_at"="excluded"."deleted_at","title"="excluded"."title","position"="excluded"."position","bought"="excluded"."bought" RETURNING "parent_list_id"
I would really like to know how to Update a Relation in Gorm or why this isn't working because I've been looking through all the Association Issues on Github and Stackoverflow and didn't find a answer that worked for me.
The first problem I see here is that your Item has no ID but uses the ParentListID as primary key. That means you can only have one Item for each parent which defeats the purpose of having an array.
Create an ID field (used as primary key) for items and if there's still issues with your approach, please update the question.
PS: would have left this in a comment, but can't.
I just needed to add the * to the []Item and fix the problem with the primarykey and remove the reference.
type Shoppinglist struct {
Model
ID int `gorm:"primaryKey" json:"id"`
Title string `json:"title"`
Items []*Item `json:"items" gorm:"foreignKey:ParentListID;"`
Owner string `json:"owner"`
Participants pq.StringArray `gorm:"type:text[]" json:"participants"`
}
type Item struct {
Model
ID int `gorm:"primaryKey" json:"id"`
ParentListID int `json:"parentListId"`
ItemID int `json:"itemId"`
Title string `json:"title"`
Position int `json:"position"`
Bought bool `json:"bought" gorm:"default:false"`
}
I keep receiving this error:
insert or update on table "note" violates foreign key constraint "note_username_fkey"
I have two tables: User and Note. Here are the create table statements:
func setup() *sql.DB {
db = connectDatabase()
//Create queries
userTable := `CREATE TABLE IF NOT EXISTS "User"(
UserID SERIAL unique,
UserName VARCHAR(50) PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
Password VARCHAR(40)
);`
noteTable := `CREATE TABLE IF NOT EXISTS Note(
NoteID SERIAL PRIMARY KEY,
UserID INT,
UserName VARCHAR(50),
Title VARCHAR(30),
Contents VARCHAR(1000),
DateCreated DATE,
DateUpdated DATE,
FOREIGN KEY (UserName) REFERENCES "User"(UserName)
);`
}
func createNoteInsertSQL(userID string, userName string, title string, content string, selectSetting string) bool {
var newNote Note
var err error
newNote.UserID, err = strconv.Atoi(userID)
if err != nil {
log.Fatal(err)
}
newNote.UserName = userName
newNote.Title = title
newNote.Contents = content
date := time.Now()
newNote.DateCreated = date
newNote.DateUpdated = date
query := `INSERT INTO Note (UserID, UserName, Title, Contents, DateCreated, DateUpdated) VALUES ($1, $2, $3, $4, $5, $6) RETURNING NoteID;`
stmt, err := db.Prepare(query)
if err != nil {
log.Fatal(err)
return false
}
var noteID int
err = stmt.QueryRow(newNote.UserID, newNote.UserName, newNote.Title, newNote.Contents, newNote.DateCreated, newNote.DateUpdated).Scan(¬eID)
if err != nil {
log.Fatal(err)
return false
}
}
Can anyone please tell me where the wrong ?
Thanks.
Check whether "Username" column value you try to insert in note table is already available in "User" table. Because the insert query is trying to insert value that is not available in "User" table.
I'm trying to create a basic commenting api in go. I can't seem to figure out how to scan postgresql arrays into an array of structs within a struct. I think I could probably have Thread.Posts type be jsonb but that seems inelegant since I would have to unmarshall it I think.
sql: Scan error on column index 3, name "posts": unsupported Scan,
storing driver.Value type []uint8 into type *[]models.Post
var threadSchema = `
CREATE TABLE IF NOT EXISTS thread (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
profile_id INTEGER REFERENCES profile (id)
)`
var postSchema = `
CREATE TABLE IF NOT EXISTS post (
id SERIAL PRIMARY KEY,
comment TEXT,
profile_id INTEGER REFERENCES profile (id),
thread_id INTEGER REFERENCES thread (id)
)`
type Post struct {
Id int `db:"id" json:"id"`
Comment string `db:"comment" json:"comment" binding:"required" form:"comment"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
ThreadId int `db:"thread_id" json:"thread_id" binding:"required" form:"thread_id"`
}
type Thread struct {
Id int `db:"id" json:"id"`
Name string `db:"name" json:"name" binding:"required" form:"name"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
Posts []Post `db:"posts" json:"posts" form:"posts"`
}
func GetThreads(db *sqlx.DB, c *gin.Context) {
threads := []Thread{}
err := db.Select(&threads, `
SELECT thread.id,thread.name,thread.profile_id,array_agg(post.id) AS posts
FROM thread
INNER JOIN post ON thread.id = post.thread_id
GROUP BY thread.id;
`)
if err != nil {
log.Fatal(err)
}
c.JSON(http.StatusOK, gin.H{"data": threads})
}
You could define your type:
type Posts []Post
// Scan implements the sql.Scanner interface.
func (a *Posts) Scan(src interface{}) error {
// ...
}
// Value implements the driver.Valuer interface.
func (a Posts) Value() (driver.Value, error) {
// ...
}
For more information on the implementation see eg here
First off, you can't do this with sqlx, whether or not you're using Postgres arrays.
Second, your SQL query is simply aggregating Post IDs, not the content of the posts, so there's no way to get the data you want (using Go or otherwise).
So here's what you can do:
Use an anonymous embedded struct, capture all of the Post content in your SQL query, and then merge your duplicated Threads.
type Post struct {
Id int `db:"id" json:"id"`
Comment string `db:"comment" json:"comment" binding:"required" form:"comment"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
ThreadId int `db:"thread_id" json:"thread_id" binding:"required" form:"thread_id"`
}
type ThreadDb struct {
Id int `db:"id" json:"id"`
Name string `db:"name" json:"name" binding:"required" form:"name"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
Post
}
type Thread struct {
Id int `db:"id" json:"id"`
Name string `db:"name" json:"name" binding:"required" form:"name"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
Posts []Post `db:"posts" json:"posts" form:"posts"`
}
func GetThreads(db *sqlx.DB, c *gin.Context) {
threads := []ThreadDb{}
err := db.Select(&threads, `
SELECT thread.id,thread.name,thread.profile_id,post.id,post.comment,post.profile_id,post.thread_id
FROM thread
INNER JOIN post ON thread.id = post.thread_id
GROUP BY post.id;
`)
thread_map := make(map[string]Thread)
for i, thread := range threads {
if _, ok := thread_map[thread.Id]; ok {
thread_map[thread.Id].Posts = append(thread_map[thread.Id].Posts, thread.Post)
} else {
thread_map[thread.Id] = Thread{thread.Id, thread.Name, thread.ProfileId, []Post{thread.Post}}
}
}
var threadSlice []string
for k := range thread_map {
threadSlice = append(threadSlice, k)
}
if err != nil {
log.Fatal(err)
}
c.JSON(http.StatusOK, gin.H{"data": threadSlice})
}
Use GROUP_CONCAT or similar. I wouldn't recommend unless you plan on having a maximum of about 100 posts per thread.
I'm using gorm and postgresql for a side-project, and I don't know how to solve this problem in 1 request:
My User type is the following:
type User struct {
UserId string
Email string
FirstName string
LastName string
Phone string
Address_1 string
Address_2 string
City string
State string
Zip string
Gender string
ImageUri string
Roles []Role `gorm:"foreignkey:UserId"`
}
My Role type is the following:
type Role struct {
UserId string
Role string
}
I want to get all users with their associated roles, but right now i'm doing this with 2 requests and I want to do it only with one:
func (s *Store) ListUsers() ([]User, error) {
users := []User{}
if err := db.Joins("join roles ON roles.user_id = users.user_id").Find(&users).Error; err != nil {
return nil, err
}
for i, user := range users {
roles := []Role{}
if err := db.Where("user_id = ?", user.UserId).Model(&Role{}).Find(&roles).Error; err != nil {
return User{}, errors.Wrap(err, "failed to get roles")
}
users[i].Roles = roles
}
return users, nil
}
I tried with several different requests, using Related etc... but my Roles slice is always empty. Any ideas ?
[EDIT] My sql schema
CREATE TABLE IF NOT EXISTS users (
user_id varchar PRIMARY KEY UNIQUE NOT NULL,
email varchar UNIQUE NOT NULL,
first_name varchar,
last_name varchar,
phone varchar,
address_1 varchar,
address_2 varchar,
city varchar,
state varchar,
zip varchar,
gender varchar,
image_uri varchar
);
CREATE TABLE IF NOT EXISTS roles (
user_id varchar REFERENCES users (user_id) ON DELETE CASCADE,
role varchar NOT NULL
);
There #har07 soultions it's probably what you need db.Preload("Roles").Find(&users) but you can't get Roles because you don't have primary key declared in you user struct, so at the end your user should look like this:
type User struct {
UserId string `gorm:"primary_key"`
Email string
FirstName string
LastName string
Phone string
Address_1 string
Address_2 string
City string
State string
Zip string
Gender string
ImageUri string
Roles []Role `gorm:"foreignkey:UserId"`
}