go-gorm how to use "where not in" query with another query - go-gorm

I need to make query "Where("users.user_id NOT IN (?)", pr)." where pr is results from another query "db.Table("partner_relationships").Select("partner_id").Where("user_id = ?", guid).Find(&pr)"
func GetAllBusinessPartners(db *gorm.DB, w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
guid := vars["id"]
results := []model.BusinessPartner{}
pr := []model.PartnerRelationship1{}
db.Table("partner_relationships").Select("partner_id").Where("user_id = ?", guid).Find(&pr)
db.Table("users").Select("users.user_id, users.first_name, users.last_name, users.profile_image, business_informations.title, business_informations.business_name").
Joins("JOIN business_informations ON users.user_id = business_informations.user_id").
Where("users.user_id != ?", guid).
Where("users.user_id NOT IN (?)", pr).
Scan(&results)
respondJSON(w, http.StatusOK, results)}
type User struct {
gorm.Model
UserID uuid.UUID `gorm:"type:uuid" json:"userID"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Gender string `json:"gender"`
Birthday time.Time `json:"birthday"`
ProfileImage string `json:"profileImage"`
}
type BusinessPartner struct {
ID uint `json:"id"`
UserID uuid.UUID `json:"userID"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
ProfileImage string `json:"profileImage"`
Title string `json:"title"`
BusinessName string `json:"businessName"`
}
type PartnerRelationship struct {
gorm.Model
UserID uuid.UUID `gorm:"type:uuid" json:"userID"`
PartnerID uuid.UUID `gorm:"type:uuid" json:"partnerID"`
Status uint `json:"status"`
ActionUserID uuid.UUID `gorm:"type:uuid" json:"actionUserID"`
}

Found the solution have to convert the struct into string
func GetAllBusinessPartners(db *gorm.DB, w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
guid := vars["id"]
results := []model.BusinessPartner{}
pr := []model.PartnerRelationship{}
db.Table("partner_relationships").Select("partner_id").Where("user_id = ?", guid).Find(&pr)
var s []string
for _, v := range pr {
s = append(s, v.PartnerID.String())
}
fmt.Printf("%q\n", s)
db.Table("users").Select("users.user_id, users.first_name, users.last_name, users.profile_image, business_informations.title, business_informations.business_name").
Joins("JOIN business_informations ON users.user_id = business_informations.user_id").
Where("users.user_id != ?", guid).
// Where("users.user_id NOT IN (?)", []string{"fbfda7f4-3691-44d0-89f2-8ccdaf3abe88", "12caf34b-42d0-4ac7-a347-a6ae1a88cb43"}).
Where("users.user_id NOT IN (?)", s).
Scan(&results)
respondJSON(w, http.StatusOK, results)
}

Related

What is it CHECK constraint failed: subject <> ''?

What is it CHECK constraint failed: subject <> '' ?
I get an error with stmt, err_execontext := s.db.ExecContext(ctx, insert, subject, description).
How can I solve this?
type TODOService struct {
db *sql.DB
}
// NewTODOService returns new TODOService.
func NewTODOService(db *sql.DB) *TODOService {
return &TODOService{
db: db,
}
}
// CreateTODO creates a TODO on DB.
func (s *TODOService) CreateTODO(ctx context.Context, subject, description string) (*model.TODO, error) {
const (
insert = `INSERT INTO todos(subject, description) VALUES(?, ?)`
confirm = `SELECT subject, description, created_at, updated_at FROM todos WHERE id = ?`
)
stmt, err_execontext := s.db.ExecContext(ctx, insert, subject, description)
if err_execontext != nil {
log.Fatal("server/todo.go 31行目", err_execontext)
}
created_id, err_iserid := stmt.LastInsertId()
if err_iserid != nil {
log.Fatal("server/todo.go 35行目", err_iserid)
}
var todo model.TODO
err := s.db.QueryRowContext(ctx, confirm, created_id).Scan(&todo.Subject, &todo.Description, &todo.CreatedAt, &todo.UpdatedAt)
switch {
case err == sql.ErrNoRows:
log.Fatalf("no todo with id %d", created_id)
case err != nil:
log.Fatal(err)
}
return &todo, err
}
type TODOHandler struct {
svc *service.TODOService
}
// NewTODOHandler returns TODOHandler based http.Handler.
func NewTODOHandler(svc *service.TODOService) *TODOHandler {
return &TODOHandler{
svc: svc,
}
}
// Create handles the endpoint that creates the TODO.
func (h *TODOHandler) Create(ctx context.Context, req *model.CreateTODORequest) (*model.CreateTODOResponse, error) {
created_todo, err := h.svc.CreateTODO(ctx, req.Subject, req.Description)
if err != nil {
log.Fatal("Failed to", err)
}
return &model.CreateTODOResponse{TODO: *created_todo}, nil
}
type (
// A TODO expresses ...
TODO struct{
ID int `json:"id"`
Subject string `json:"subject"`
Description string `json:"description"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
}
// A CreateTODORequest expresses ...
CreateTODORequest struct{
Subject string `json:"subject"`
Description string `json:"description"`
}
// A CreateTODOResponse expresses ...
CreateTODOResponse struct{
TODO TODO `json:"todo"`
}
)
What is it CHECK constraint failed: subject <> '' ?
I get an error with stmt, err_execontext := s.db.ExecContext(ctx, insert, subject, description).
How can I solve this?
CREATE TABLE IF NOT EXISTS todos (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
subject TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
created_at DATETIME NOT NULL DEFAULT (DATETIME('now')),
updated_at DATETIME NOT NULL DEFAULT (DATETIME('now')),
CHECK(subject <> '')
);
CREATE TRIGGER IF NOT EXISTS trigger_todos_updated_at AFTER UPDATE ON todos
BEGIN
UPDATE todos SET updated_at = DATETIME('now') WHERE id == NEW.id;
END;

Filtering and sorting an SQL query to recreate a nested struct

I am new to Go and I'm trying to populate a struct called Reliefworker from an SQL query which I can send as a JSON payload.
Essentially I have a Reliefworker who may be assigned to many communities and the community can consist of multiple regions.
I suspect there is a clever way of doing this other than what I intend which is a primitive solution that will add a sort to the SQL (by Community) and create a function that detects if the community being added is different to the previous one, in which case I would create a new community struct type object to be appended.
type Reliefworker struct {
Name string `json:"name"`
Communities []Community `json:"community"`
Deployment_id string `json:"deployment_id"`
}
type Community struct{
Name string `json:"name"`
community_id string `json:"community_id"`
Regions []Region `json:"regions"`
}
type Region struct{
Name string `json:"name"`
Region_id string `json:"region_id"`
Reconstruction_grant string `json:"reconstruction_grant"`
Currency string `json:"currency"`
}
Currently I have created a struct that reflects what I am actually getting from SQL whilst pondering my next move. Perhaps this might be a good stepping stone instead of attempting an on-the-fly transformation ?
type ReliefWorker_community_region struct {
Deployment_id string
Community_title int
Region_name string
Reconstruction_grant int
}
func GetReliefWorkers(deployment_id string) []Reliefworker {
fmt.Printf("Confirm I have a deployment id:%v\n", deployment_id)
rows, err := middleware.Db.Query("select deployment_id, community_title, region_name, reconstruction_grant WHERE Deployment_id=$1", brand_id)
if err != nil {
return
}
for rows.Next() {
reliefworker := Reliefworker{}
err = rows.Scan(&deployment_id, &community_title, &region_name, &reconstruction_grant)
if err != nil {
return
}
}
rows.Close()
return
}
I think a sort makes a lot of sense, primitive solutions can be the most efficient:
func GetReliefWorkers(deployment_id string) []Reliefworker {
// Added sort to query
q := "select worker_name, community_title, region_name, reconstruction_grant WHERE deployment_id=? ORDER BY community_title"
rows, err := middleware.Db.Query(q, deployment_id)
if err != nil {
return
}
defer rows.Close() // So rows get closed even on an error
c := Community{} // To keep track of the current community
cmatrix := [][]string{[]string{}} // Matrix of communities and workers
communities := []Community{} // List of communities
workers := make(map[string]Reliefworker) // Map of workers
var ccount int // Index of community in lists
for rows.Next() {
w := Reliefworker{Deployment_id: deployment_id}
r := Region{}
var ctitle string // For comparison later
err = rows.Scan(&w.Name, &ctitle, &r.Name, &r.Reconstruction_grant)
if err != nil {
return
}
if ctitle != c.Name {
communities = append(communities, c)
c = Community{}
c.Name = ctitle
ccount++
cmatrix = append(cmatrix, []string{})
}
c.Regions = append(c.Regions, r)
cmatrix[ccount] = append(cmatrix[ccount], w.Name)
workers[w.Name] = w
}
for i, c := range communities {
for _, id := range cmatrix[i] {
w := workers[id] // To avoid error
w.Communities = append(w.Communities, c)
workers[id] = w
}
}
out := []Reliefworker{}
for _, w := range workers {
out = append(out, w)
}
return out
}
Though it might make even more sense to create seperate tables for communities, regions, and workers, then query them all with a JOIN: https://www.w3schools.com/sql/sql_join_inner.asp
UPDATE: Since you only want to retrieve one Reliefworker, would something like this work?
type ReliefWorker struct {
Name string `json:"name"`
Communities []Community `json:"community"`
}
type Community struct {
Name string `json:"name"`
Regions []Region `json:"regions"`
}
type Region struct {
Name string `json:"name"`
Region_id string `json:"region_id"`
Reconstruction_grant int `json:"reconstruction_grant"`
Currency string `json:"currency"`
}
func GetReliefWorkers(deployment_id string) Reliefworker {
reliefworker := Reliefworker{}
communities := make(map[string]Community)
rows, err := middleware.Db.Query("select name, community_title, region_name, region_id, reconstruction_grant WHERE Deployment_id=$1", deployment_id)
if err != nil {
if err == sql.ErrNoRows {
fmt.Printf("No records for ReliefWorker:%v\n", deployment_id)
}
panic(err)
}
defer rows.Close()
for rows.Next() {
c := Community{}
r := Region{}
err = rows.Scan(&reliefworker.Name, &c.Name, &r.Name, &r.Region_id, &r.Reconstruction_grant)
if err != nil {
panic(err)
}
if _, ok := communities[c.Name]; ok {
c = communities[c.Name]
}
c.Regions = append(c.Regions, r)
communities[c.Name] = c
}
for _, c := range commmunities {
reliefworker.Communities = append(reliefworker.Communities, c)
}
return reliefworker
}
Ok, my crude solution doesn't contain a shred of the intelligence #Absentbird demonstrates but I'm here to learn.
#Absentbird I love your use of maps and multidimensional arrays to hold a matrix of communities and workers. I will focus on making this part of my arsenal over the weekend.
I can accept and adapt #Absentbird's solution once I have a solution to why it gives the error "cannot assign to struct field workers[id].Communities in mapcompilerUnaddressableFieldAssign" for the line workers[id].Communities = append(workers[id].Communities, c)
Firstly apologies as I had to correct two things. Firstly I only needed to return ReliefWorkers (not an array of ReliefWorkers). Secondly ReliefWorker struct did not need to contain the Deployment_id since I already knew it.
I am new to Go so I'd really appreciate feedback on what I can do to better leverage the language and write more concise code.
My structs and solution is currently as follows:
type ReliefWorker struct {
Name string `json:"name"`
Communities []Community `json:"community"`
}
type Community struct {
Name string `json:"name"`
Regions []Region `json:"regions"`
}
type Region struct {
Name string `json:"name"`
Region_id string `json:"region_id"`
Reconstruction_grant int `json:"reconstruction_grant"`
Currency string `json:"currency"`
}
type ReliefWorker_community_region struct {
Name string
Community_title string
Region_name string
Reconstruction_grant int
}
func GetReliefWorkers(deployment_id string) Reliefworker {
var reliefworker Reliefworker
var communitiesOnly []string
var name string
var allReliefWorkerData []ReliefWorker_community_region
rows, err := middleware.Db.Query("select name, community_title, region_name, reconstruction_grant WHERE Deployment_id=$1", deployment_id)
for rows.Next() {
reliefWorker_community_region := ReliefWorker_community_region{}
err = rows.Scan(&reliefWorker_community_region.Name, &reliefWorker_community_region.Community_title, &reliefWorker_community_region.Region_name, &reliefWorker_community_region.Reconstruction_grant)
if err != nil {
panic(err)
}
name = reliefWorker_community_region.Name
allReliefWorkerData = append(allReliefWorkerData, reliefWorker_community_region)
communitiesOnly = append(communitiesOnly, reliefWorker_community_region.Community_title) //All communities go in here, even duplicates, will will create a unique set later
}
rows.Close()
if err != nil {
if err == sql.ErrNoRows {
fmt.Printf("No records for ReliefWorker:%v\n", deployment_id)
}
panic(err)
}
var unique []string //Use this to create a unique index of communities
for _, v := range communitiesOnly {
skip := false
for _, u := range unique {
if v == u {
skip = true
break
}
}
if !skip {
unique = append(unique, v)
}
}
fmt.Println(unique)
reliefworker.Name = name
var community Community
var communities []Community
for _, v := range unique {
community.Name = v
communities = append(communities, community)
}
// Go through each record from the database held within allReliefWorkerData and grab every region belonging to a Community, when done append it to Communities and finally append that to ReliefWorker
for j, u := range communities {
var regions []Region
for i, v := range allReliefWorkerData {
if v.Community_title == u.Name {
var region Region
region.Name = v.Region_name
region.Reconstruction_grant = v.Reconstruction_grant
regions = append(regions, region)
}
}
communities[j].Regions = regions
}
reliefworker.Communities = communities
return reliefworker
}

db.Query with sql join error Scan error on column

error!!!
Scan error on column index 1, name "url": unsupported Scan, storing driver.Value type []uint8 into type *[]handle.Movie
https://gyazo.com/7532a1c3793c892e721054998865609d
https://gyazo.com/278066e6da16f13cd9c56874beb71026
type Movie struct {
ID int
Url string
CategoryID uint
}
type Category struct {
ID int
Name string
Movies []Movie
}
func Connected() []Category {
db := ConnectDB()
defer db.Close()
//sql
query := `SELECT c.name,m.url FROM categories c left join movies m on c.id = m.category_id`
rows, err := db.Query(query)
if err != nil {
log.Fatal(err)
}
var sli []Category
var v1 Category
for rows.Next() {
if err := rows.Scan(&v1.Name, &v1.Movies); err != nil {
log.Fatal(err)
}
sli = append(sli, v1)
}
fmt.Println(sli[0].Movies)
return sli
}
I want to achieve this result!!!
[{1 aaa [https//you...,https//you...],2 bbb [https/you...]}]
I want to get a movie that is linked by category association by slice
-----------------------------PS ---------------------------------
This is what I wanted to do!!!
func Connected() []Category {
db := ConnectDB()
defer db.Close()
//sql
query := `SELECT c.id, c.name, m.id, m.url FROM categories c left join movies m on c.id = m.category_id ORDER BY c.id ASC`
rows, err := db.Query(query)
if err != nil {
log.Fatal(err)
}
var sli []Category
var c Category
var m Movie
for rows.Next() {
if err := rows.Scan(&c.ID, &c.Name, &m.ID, &m.Url); err != nil {
log.Fatal(err)
}
m.CategoryID = c.ID
l := len(sli)
if l > 0 && sli[l-1].ID == c.ID {
sli[l-1].Movies = append(sli[l-1].Movies, m)
} else {
if len(c.Movies) != 0 {
c.Movies = remove(c.Movies, c.Movies[0])
}
c.Movies = append(c.Movies, m)
sli = append(sli, c)
}
}
return sli
}
func remove(ints []Movie, search Movie) []Movie {
result := []Movie{}
for _, v := range ints {
if v != search {
result = append(result, v)
}
}
return result
}
Thanks everyone
well as I see you are trying to store a single URL into an array of Movie struct which is impossible.
your query may return all URLs for each category but each URL is in a single row and you should aggregate them your self.
and as I know you should scan data into Golang default types, not your custom structs. mapping your data into your custom struct is a different thing.
this is a sample code but I don't have access to your database so I can't test it but it should work as you want.
type Movie struct {
ID int
Url string
CategoryID uint
}
type Category struct {
ID int
Name string
Movies []Movie
}
func Connected() []Category {
db := ConnectDB()
defer db.Close()
//sql
query := `SELECT c.id, c.name, m.id, m.url FROM categories c left join movies m on c.id = m.category_id
ORDER BY c.id ASC`
rows, err := db.Query(query)
if err != nil {
log.Fatal(err)
}
var sli []Category
var v1 Category
var m Movie
for rows.Next() {
if err := rows.Scan(&v1.ID, &v1.Name, &m.ID, &m.Url); err != nil {
log.Fatal(err)
}
m.CategoryID = v1.ID
l := len(sli)
if l > 0 && sli[l - 1].ID == v1.ID {
sli[l - 1].Movies = append(sli[l - 1].Movies, m)
} else {
v1.Movies = append(v1.Movies, m)
sli = append(sli, v1)
}
}
fmt.Println(sli[0].Movies)
return sli
}

beego api post insert data

First of all. I use postman to POST data. How to take data from the postman key.
It works by using this way (in my code I set it by myself).
I want to get firstname, lastname, email in form-data.
I want to use as below.
func InsertOneUser(user User) *User {
o := orm.NewOrm()
qs := o.QueryTable(new(User))
i, _ := qs.PrepareInsert()
var u User
user.FirstName = "firstname" <----- this
user.LastName = "lastname" <----- this
user.Email = "something#yahoo.com" <----- this
user.Password, _ = hashPassword(user.Password)
user.RegDate = time.Now()
id, err := i.Insert(&user)
return &u
}
You need beego.Controller in func. if func has beego.Controller, there are two ways(key, parseform).
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type User struct {
Firstname string `form:"firstname"`
Lastname string `form:"lastname"`
Email string `form:"email"`
}
type MainController struct {
beego.Controller
}
func (this *MainController) Post() {
// using key
firstname := this.GetString("firstname")
lastname := this.GetString("lastname")
email := this.GetString("email")
// using Parseform
u := User{}
if err := this.ParseForm(&u); err != nil {
fmt.Println(err)
}
fmt.Println(u)
this.Ctx.WriteString(fmt.Sprintf("%s %s %s", firstname, lastname, email))
}
func main() {
beego.Router("/api/v1/user", &MainController{})
beego.Run()
}

Controlling a Pointer in Go

I am trying to iterate through rows after it does a query to a database but I'm having trouble iterating through it a second time to find the females.
I believe this is because of the fact that after it iterates through rows printing out the men, the pointer is left at the end and can't go back.
rows2, rowErr :=db.Query("SELECT GIVENNAME,gender, count(givenname) as Frequency from people group by givenname order by givenname asc")
for rows2.Next() {
nextErr := rows2.Scan(&givenName,&gender, &frequency)
if nextErr != nil{
log.Fatal(nextErr.Error())
}
if gender == "male" {
fmt.Println(givenName, gender, frequency)
}
}
fmt.Println("")
for rows2.Next() {
nextErr := rows2.Scan(&givenName,&gender, &frequency)
if nextErr != nil{
log.Fatal(nextErr.Error())
}
if gender == "female" {
fmt.Println(givenName, gender, frequency)
}
}
How can I put the pointer at the beginning again? Or will I have to do another query?
You can't 'rollback' a pointer to a previous value, hence you have to use another (temporary) var which you use to iterate.
rows2, rowErr := db.Query("SELECT GIVENNAME, gender, count(givenname) as Frequency from people group by givenname order by givenname asc")
var list1, list2 MyPeopleStruct
temp := rows2
for temp.Next() {
nextErr := rows2.Scan(&givenName,&gender, &frequency)
if nextErr != nil{
log.Fatal(nextErr.Error())
}
if gender == "male" {
fmt.Println(givenName, gender, frequency)
}
}
fmt.Println("")
temp = rows2 // reinitialise it to the actual value you need
for temp.Next() {
nextErr := rows2.Scan(&givenName,&gender, &frequency)
if nextErr != nil{
log.Fatal(nextErr.Error())
}
if gender == "female" {
fmt.Println(givenName, gender, frequency)
}
}
Anyway, why do you even need to make two different for loops?
Can't you do everything using only one? like:
type MyPeopleStruct struct{
Gender string
Name string
Frequency int
}
rows2, rowErr := db.Query("SELECT GIVENNAME, gender, count(givenname) as Frequency from people group by givenname order by givenname asc")
var listM, listF []MyPeopleStruct
temp := rows2
for temp.Next() {
nextErr := rows2.Scan(&givenName,&gender, &frequency)
if nextErr != nil{
log.Fatal(nextErr.Error())
}
if gender == "male" {
fmt.Println(givenName, gender, frequency)
listM = append(listM, MyPeopleStruct{gender,givenName,frequency})
}
if gender == "female" {
fmt.Println(givenName, gender, frequency)
listF = append(listF, MyPeopleStruct{gender,givenName,frequency})
}
}
// Use listM and listF