Summary
Tried to implement DUPLICATE: Bidirectional many2many relationship solution. After appending different users to the "Followings" and "Followers" fields, any user added to the Following field is also being added to Followers field, and vice versa.
The same happens with BlockedBy and Blocking fields.
I defined User Following and Blockingstruct types as follows
type User struct {
Email string `gorm:"size:100;not null;unique" json:"email"`
...
UserId string `gorm:"primary_key;not null" json:"userid"`
}
type Following struct {
ID string `gorm:"primary_key" json:"id"`
User User `gorm:"foreignKey:ID;references:UserId"`
Followings []*User `gorm:"many2many:user_relation;foreignKey:ID;joinForeignKey:UserA;references:UserId;joinReferences:UserB;constraint:OnDelete:CASCADE"`
Followers []*User `gorm:"many2many:user_relation;foreignKey:ID;joinForeignKey:UserB;references:UserId;joinReferences:UserA;constraint:OnDelete:CASCADE"`
}
type Blocking struct {
ID string `gorm:"primary_key" json:"id"`
User User `gorm:"foreignKey:ID"`
BlockedBy []*User `gorm:"many2many:user_blocks;foreignKey:ID;joinForeignKey:UserIdBlocked;joinReferences:UserId;constraint:OnDelete:CASCADE"`
Blocking []*User `gorm:"many2many:user_blocks;foreignKey:ID;joinForeignKey:UserId;joinReferences:userIdBlocked;constraint:OnDelete:CASCADE"`
}
Loading method
Here's how I first initialized and load some data for testing purposes:
// Load autogenerates the tables and records
func Load() {
db, err := database.Connect()
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Creates table for each model
err = db.Debug().DropTableIfExists(
&models.User{},
&models.Following{},
&models.Blocking{},
).Error
if err != nil {
log.Fatal(err)
}
//ERROR while using Postgres on Post model
err = db.Debug().AutoMigrate(
&models.User{},
&models.Following{},
&models.Blocking{},
).Error
if err != nil {
log.Fatal(err)
}
for i, _ := range users {
err = db.Debug().Model(&models.User{}).Create(&users[i]).Error
if err != nil {
log.Fatal(err)
}
userfollowings[i].ID = users[i].UserId
blocked_users[i].ID = users[i].UserId
err = db.Debug().Model(&models.Following{}).Create(&userfollowings[i]).Error
if err != nil {
log.Fatal(err)
}
blocked_users[i].ID = users[i].UserId
err = db.Debug().Model(&models.Blocking{}).Create(&blocked_users[i]).Error
if err != nil {
log.Fatal(err)
}
err = db.Debug().Model(&userfollowings[i]).Related(&userfollowings[i].User, "user_id").Error
if err != nil {
log.Fatal(err)
}
err = db.Debug().Model(&blocked_users[i]).Related(&blocked_users[i].User, "user_id").Error
if err != nil {
log.Fatal(err)
}
if i == 0 {
err = db.Model(&userfollowings[i]).Association("Followings").Append(&users[1], &users[2]).Error
if err != nil {
log.Fatal(err)
}
} else if i == 1 {
err = db.Model(&userfollowings[i]).Association("Followings").Append(&users[2]).Error
if err != nil {
log.Fatal(err)
}
} else if i == 2 {
err = db.Model(&userfollowings[i]).Association("Followings").Append(&users[3]).Error
if err != nil {
log.Fatal(err)
}
} else if i == 3 {
err = db.Model(&userfollowings[i]).Association("Followings").Append(&users[0]).Error
if err != nil {
log.Fatal(err)
}
fo_info := models.Following{}
if err != nil {
log.Fatal(err)
}
console.Pretty(&fo_info)
}
}
}
Displaying Following model query result for UserId: 4
[2021-12-27 12:17:03] [0.90ms] SELECT * FROM `users` INNER JOIN `user_relation` ON `user_relation`.`user_user_id` = `users`.`user_id` WHERE (`user_relation`.`following_id` IN ('4'))
[0 rows affected or returned ]
{
"id": "4",
"User": {
"email": "q4#gmail.com",
"id": "4",
"displayName": "John Lennon",
},
"Followings": [
{
"email": "q#gmail.com",
...,
"userid": "1",
"displayName": "Ringo Starr",
},
],
"Followers": [
{
"email": "q#gmail.com",
...
"userid": "1",
"displayName": "Ringo Starr",
}
]
}
Expected result
[2021-12-27 12:17:03] [0.90ms] SELECT * FROM `users` INNER JOIN `user_relation` ON `user_relation`.`user_user_id` = `users`.`user_id` WHERE (`user_relation`.`following_id` IN ('4'))
[0 rows affected or returned ]
{
"id": "4",
"User": {
"email": "q4#gmail.com",
"id": "4",
"displayName": "John Lennon",
},
"Followings": [
{
"email": "q#gmail.com",
...,
"userid": "1",
"displayName": "Ringo Starr",
},
],
"Followers": [
{
"email": "q2#gmail.com",
...
"userid": "2",
"displayName": "George Harrison",
}
]
}
Since last Friday, I'm unable to make this working out. Tried different resource from Golang Gorm documentation and searched similar SOF Q&A, which didn't provide me any solution or guidance.
Related
tmpbyte, _ := json.Marshal(vdata["user"])
fmt.Println(string(tmpbyte))
I got this data from mongodb,
[
{
"avatar_image": "https://i6e.jpg",
"display_name": "flash.info",
"image_user": "",
"user_id": "qXGFIa",
"username": "flash.info"
},
{
"avatar_image": "https://847a",
"display_name": "Akhmad Jazuli",
"image_user": "",
"user_id": "mf7EXj",
"username": "akhmad.jazuli"
},
{
"avatar_image": "https://i-stageb10a.jpg",
"display_name": " Alfan Rey",
"image_user": "",
"user_id": "bsiAlG",
"username": "fn.alfan"
}
]
how to get only loop of user_id from this data?
user_id1
user_id2
user_id1
The first step is to create a data structure for your entities about users and then decode the data using MongoDB.
type User struct {
Id primitive.ObjectID `bson="_id"`
AvatarImage string `bson="avatar_image"`
DisplayName string `bson="display_name"`
UserId string `bson="user_id"`
UserName string `bson="username"`
}
func GetUserIds(ctx context.Context) ([]string, error) {
userIds := make([]string, 0)
cur, err := collectionUser.Find(ctx, nil)
if err != nil {
return nil, err
}
for cur.Next(ctx) {
user := new(User)
if err := cur.Decode(user); err != nil {
return nil, err
}
userIds = append(userIds, user.UserId)
}
return userIds, nil
}
}
I am new to backend and as well as golang and gorm.
I'm learning backend by building simple api with has-many in go and gorm.
I'm try to create "Trip" table and "SingleTrip" table with foreign key of "TripId"
basically, a trip has a slice of singleTrip
Here the code,
I have two models which is
type Base struct {
gorm.Model
ID string `gorm:"primary_key;not_null" json:"id"`
}
type Trip struct {
Base
UserId string `gorm:"not_null" json:"user_id"`
TripDetail []SingleTrip `gorm:"foreignKey:Id;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"trip_detail"`
}
type SingleTrip struct {
gorm.Model
Id string `gorm:"primary_id" json:"id"`
TripId string `gorm:"primary_key;not_null" json:"trip_id"`
TripDate string `gorm:"size:255;not_null;" json:"trip_date"`
FromAddress string `gorm:"size:255;not_null;" json:"from_address"`
ToAddress string `gorm:"size:255;not_null;" json:"to_address"`
Distance float64 `gorm:"not_null;" json:"distance"`
Reason string `gorm:"size:255;not_null;" json:"reason"`
Comments string `gorm:"size:255;not_null;" json:"comments"`
Receipts string `gorm:"size:255;not_null;" json:"receipt"`
Amount float64 `gorm:"not_null;" json:"amount"`
RoundTrip string `gorm:"size:255;not_null;" json:"round_trip"`
}
func (trip *Trip) BeforeCreate(gorm *gorm.DB) error {
tripId := uuid.New()
trip.ID = tripId.String()
return nil
}
func (singleTrip *SingleTrip) BeforeCreate(gorm *gorm.DB) error {
id := uuid.New()
singleTrip.Id = id.String()
return nil
}
this is the request body i've try to save in mysql db
{
"user_id": "d4be5cbc-4377-11ec-a108-2e7a8ebc414a",
"trip_detail": [
{
"trip_date": "05/29/2021",
"from_address":"from address field",
"to_address": "to address field",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comments field",
"receipt": "for lunch",
"amount": 50.0,
"round_trip": "round field"
},
{
"trip_date": "07/29/2021",
"from_address": "some address",
"to_address": "Some to address",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comment field",
"receipt": "for meeting",
"amount": 50.0,
"round_trip": "round field"
}
]
}
this is SaveTrip methods
func (trip *Trip) SaveTrip(db *gorm.DB) (*Trip, error) {
err := db.Debug().Create(&trip).Error
if err != nil {
return &Trip{}, err
}
return trip, nil
}
controller
trip_controller.go
func (server *Server) CreateTrip(context *gin.Context) {
errMessage := map[string]string{}
body, err := ioutil.ReadAll(context.Request.Body)
trip := models.Trip{}
if err != nil {
errMessage["Invalid Request"] = "Invalid Request"
context.JSON(http.StatusUnprocessableEntity, gin.H{
"status": http.StatusUnprocessableEntity,
"error": errMessage,
})
return
}
err = json.Unmarshal([]byte(body), &trip)
if err != nil {
errMessage["Unable to Unmarshall"] = "Unable to unmarshal"
context.JSON(http.StatusUnprocessableEntity, gin.H{
"status": http.StatusUnprocessableEntity,
"error": errMessage,
})
return
}
trip.Prepare()
validatingErrMessage := map[string]string{}
validatingErrMessage = trip.ValidatingTripData("create")
if len(validatingErrMessage) > 0 {
errMessage = validatingErrMessage
context.JSON(http.StatusUnprocessableEntity, gin.H{
"status": http.StatusUnprocessableEntity,
"error": errMessage,
})
return
}
createdTrip, err := trip.SaveTrip(server.DB)
if err != nil {
formattedError := utils.FormatError(err.Error())
context.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"status": http.StatusOK,
"response": createdTrip,
})
}
this is the response i'm getting from postman
{
"response": {
"ID": 0,
"CreatedAt": "2021-11-18T00:08:55.357+05:30",
"UpdatedAt": "2021-11-18T00:08:55.357+05:30",
"DeletedAt": null,
"id": "52a44faa-437a-4695-82c7-b45cdab9e6d1",
"user_id": "d4be5cbc-4377-11ec-a108-2e7a8ebc414a",
"trip_detail": [
{
"ID": 0,
"CreatedAt": "2021-11-18T00:08:55.362+05:30",
"UpdatedAt": "2021-11-18T00:08:55.362+05:30",
"DeletedAt": null,
"Id": "52a44faa-437a-4695-82c7-b45cdab9e6d1",
"trip_date": "05/29/2021",
"from_address": "some address",
"to_address": "some - to address",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comments field",
"receipt": "for lunch",
"amount": 50,
"round_trip": "round field"
},
{
"ID": 0,
"CreatedAt": "2021-11-18T00:08:55.362+05:30",
"UpdatedAt": "2021-11-18T00:08:55.362+05:30",
"DeletedAt": null,
"Id": "52a44faa-437a-4695-82c7-b45cdab9e6d1",
"trip_date": "07/29/2021",
"from_address": "some address",
"to_address": "Some to address",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comment field",
"receipt": "for meeting",
"amount": 50,
"round_trip": "round field"
}
]
},
"status": 200
}
but data's not store in DB
when try to store data to db, i am getting below error
How to store the data in Db, or is there any other way to store the value?
I am using golang, gorm, gin framework.
Sorry If I have bad grammar.
Change this line of code
func (singleTrip *SingleTrip) BeforeCreate(gorm *gorm.DB) error {
/*
fmt.Println(singleTrip.Id) // this value will be Trip (parent) ID
*/
id := uuid.New()
// WRONG
// singleTrip.Id = id.String()
/*
Maybe This is what you want
TripId is the primary Key
not Id (from how you define the model tag)
*/
singleTrip.TripId = id.String()
return nil
}
Id in SingleTrip (in this case, is a foreign key, not the primary key) must not be overwritten with BeforeCreate because gorm relation already handles the Id value to be ID from Trip (parent). You can try to log the value if you want.
This will cause an error in MySQL itself because in the transaction the new id is not recorded in the parent (Trip) Primary Key.
And a little suggestion, Be Wise to choose the foreign key name, like trip_id is good for Trip x SingleTrip foreign key instead of Id. It is confusing to understand the model at first.
Full Code:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
func main() {
databaseConfig := fmt.Sprintf("%s:%s#tcp(%s:%s)/%s?multiStatements=true&parseTime=true", "root", "", "127.0.0.1", "3306", "tester")
DB, _ = gorm.Open(mysql.Open(databaseConfig), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
sqlDB, _ := DB.DB()
defer sqlDB.Close()
DB.AutoMigrate(&Trip{}, &SingleTrip{})
router := gin.Default()
router.POST("/", CreateTrip)
router.Run(":8080")
}
type Base struct {
gorm.Model
ID string `gorm:"primary_key;not_null" json:"id"`
}
type Trip struct {
// Base
gorm.Model
ID string `gorm:"size:255;primary_key;not_null" json:"id"`
UserId string `gorm:"not_null" json:"user_id"`
TripDetail []SingleTrip `gorm:"foreignKey:Id;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"trip_detail"`
}
type SingleTrip struct {
gorm.Model
Id string `gorm:"size:255;primary_id" json:"id"`
TripId string `gorm:"primary_key;not_null" json:"trip_id"`
TripDate string `gorm:"size:255;not_null;" json:"trip_date"`
FromAddress string `gorm:"size:255;not_null;" json:"from_address"`
ToAddress string `gorm:"size:255;not_null;" json:"to_address"`
Distance float64 `gorm:"not_null;" json:"distance"`
Reason string `gorm:"size:255;not_null;" json:"reason"`
Comments string `gorm:"size:255;not_null;" json:"comments"`
Receipts string `gorm:"size:255;not_null;" json:"receipt"`
Amount float64 `gorm:"not_null;" json:"amount"`
RoundTrip string `gorm:"size:255;not_null;" json:"round_trip"`
}
func (trip *Trip) BeforeCreate(gorm *gorm.DB) error {
tripId := uuid.New()
trip.ID = tripId.String()
return nil
}
func (singleTrip *SingleTrip) BeforeCreate(gorm *gorm.DB) error {
/*
fmt.Println(singleTrip.Id) // this value will be Trip (parent) ID
*/
id := uuid.New()
// WRONG
// singleTrip.Id = id.String()
/*
Maybe This is what you want
TripId is the primary Key
not Id (from how you define the model tag)
*/
singleTrip.TripId = id.String()
return nil
}
func (trip *Trip) SaveTrip(db *gorm.DB) (*Trip, error) {
err := db.Debug().Create(&trip).Error
if err != nil {
return &Trip{}, err
}
return trip, nil
}
// =======================================================
func CreateTrip(context *gin.Context) {
errMessage := map[string]string{}
body, err := ioutil.ReadAll(context.Request.Body)
trip := Trip{}
if err != nil {
errMessage["Invalid Request"] = "Invalid Request"
context.JSON(http.StatusUnprocessableEntity, gin.H{
"status": http.StatusUnprocessableEntity,
"error": errMessage,
})
return
}
err = json.Unmarshal([]byte(body), &trip)
if err != nil {
errMessage["Unable to Unmarshall"] = "Unable to unmarshal"
context.JSON(http.StatusUnprocessableEntity, gin.H{
"status": http.StatusUnprocessableEntity,
"error": errMessage,
})
return
}
fmt.Printf("Trip: %+v", trip)
// fmt.Printf("Trip: %+v", trip.TripDetail[0].ID)
// fmt.Printf("Trip: %+v", trip.TripDetail[0].Id)
// trip.Prepare()
// validatingErrMessage := map[string]string{}
// validatingErrMessage = trip.ValidatingTripData("create")
// if len(validatingErrMessage) > 0 {
// errMessage = validatingErrMessage
// context.JSON(http.StatusUnprocessableEntity, gin.H{
// "status": http.StatusUnprocessableEntity,
// "error": errMessage,
// })
// return
// }
createdTrip, err := trip.SaveTrip(DB)
if err != nil {
// formattedError := utils.FormatError(err.Error())
context.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"status": http.StatusOK,
"response": createdTrip,
})
}
Output
I need to add an array of string to a json file.
i.e let's say i have the following json file:
{
"user": {
"role": "admin",
"email": "admin#domain.com"
},
"region": [
{
"location": "EU",
"currency": "EUR",
"countries": [
{
"FR": [
{
"time": "morning",
"cities": []
}
]
}
]
},
{
"location": "NA",
"currency": "USD",
"countries": [
{
"USA": [
{
"time": "evening",
"cities": []
}
]
}
]
}
]
}
Now lets say I have a list of cities that I want to add to region -> countries -> FR
This is my approach, but not sure how to update the cities field.
I have commented the section in the code that need to store to update the list of cities for FA.
func test (jsonFilePath, cityNames string) error {
jsonBytes, err := ioutil.ReadFile(jsonFile)
if err != nil {
return err
}
fmt.Printf("template json file is %s\n", jsonBytes)
var result map[string]interface{}
err = json.Unmarshal(jsonBytes, &result)
if err != nil {
return err
}
if _, exists := result["region"]; exists {
fmt.Printf("Found region\n")
countries := result["region"].([]interface{})
for _, country := range countries {
m := country.(map[string]interface{})
if _, exists := m["FR"]; exists {
/*How to add cityNames to the cities array of the FA?*/
}
}
} else {
errMsg := "region field is missing"
return errors.New(errMsg)
}
jsonBytes, err = json.Marshal(result)
if err != nil {
return err
}
fmt.Printf("the new json file is %s\n", string(jsonBytes))
// Write back to file
err = ioutil.WriteFile("newJson.json", jsonBytes, 0644)
return err
}
Note: The json file has other fields which should not be updated, only Cities filed should be updated; so the preference is to update the Cities field only without defining a struct
Normally it's better (i.e. easier and more efficient) to use structs instead of reflection. There are even websites that can generate a struct from a JSON sample.
But here's how to do it using maps of interfaces:
var result map[string]interface{}
err := json.Unmarshal(jsonBytes, &result)
if err != nil {
return nil, err
}
regions, ok := result["region"].([]interface{})
if !ok {
return nil, errors.New("region not found")
}
for i := range regions {
region, ok := regions[i].(map[string]interface{})
if !ok {
continue
}
countries, ok := region["countries"].([]interface{})
if !ok {
continue
}
for j := range countries {
country, ok := countries[j].(map[string]interface{})
if !ok {
continue
}
fr, ok := country["FR"].([]interface{})
if !ok {
continue
}
for k := range fr {
time, ok := fr[k].(map[string]interface{})
if !ok {
continue
}
cities, ok := time["cities"].([]interface{})
if !ok {
continue
}
time["cities"] = append(cities, cityNames)
}
}
}
Note that in Go maps do not preserve the order, so the order of fields in the output will be different (and also random between runs).
I have the following code
func Employees(db *database.Database) fiber.Handler {
return func(c *fiber.Ctx) error {
var employees []model.Employee
if response := db.Preload(clause.Associations).Find(&employees); response.Error != nil {
return c.JSON(responseKit.RecordNotFoundError())
}
return c.JSON(responseKit.RecordsFoundSuccess(employees, len(employees)))
}
}
func CreateEmployee(db *database.Database) fiber.Handler {
return func(c *fiber.Ctx) error {
employee := new(model.Employee)
if err := c.BodyParser(employee); err != nil {
fmt.Printf("%v", err)
return c.JSON(responseKit.ParsingError())
}
// if err := employee.Validate(); err != nil {
// return c.JSON(responseKit.ValidationError(err))
// }
if result := db.Preload(clause.Associations).Omit(clause.Associations).Create(&employee); result.Error != nil {
return c.JSON(responseKit.RecordCreateError())
}
return c.JSON(responseKit.RecordCreateSuccess(employee))
}
}
Where I preload all the associations when finding employees. This works as expected and I get the employees with their associations preloaded. Where the associations look like this in the response json
"groupID": 1,
"group": {
"id": 1,
"title": "Test"
},
"roleID": 1,
"role": {
"id": 1,
"title": "Test"
}
But when I create an employee preloading doesn't work. So the response I get back has no group or role data only the ID
"groupID": 1,
"group": {
"id": 0,
"title": ""
},
"roleID": 1,
"role": {
"id": 0,
"title": ""
}
This is my employee model
type Employee struct {
PrivateGormModel
Person `gorm:"embedded" json:"person,omitempty"`
Contact `gorm:"embedded" json:"contact,omitempty"`
Address `gorm:"embedded" json:"address,omitempty"`
AltContact `gorm:"embedded" json:"privateContact,omitempty"`
BankAccount `gorm:"embedded" json:"bankAccount,omitempty"`
GroupID uint `json:"groupID"`
Group EmployeeGroup `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"group"`
RoleID uint `json:"roleID"`
Role EmployeeRole `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"role"`
}
How can I preload the data when I create the entry? In this case the group and role already have entries in the database so I create the employee entry with an ID that points to that role and group. I do that with the following json
{
"person":{
"initials":"",
"firstName":"",
"middleName":"",
"lastName":"",
"dateOfBirth":"",
"language":""
},
"address":{
"country":"",
"zip":"",
"number":"0",
"addition":"",
"street":"",
"state":"",
"city":""
},
"contact":{
"tel":"",
"mail":"",
"url":""
},
"bankAccount":{
"bank":"",
"bic":"",
"iban":"",
"accountHolder":"",
"establishment":""
},
"roleID":1,
"groupID":1
}
it's not working because, you have omitted clause.Associations in CreateEmployee Function
existing snippet \/
if result := db.Preload(clause.Associations).Omit(clause.Associations).Create(&employee); result.Error != nil {
return c.JSON(responseKit.RecordCreateError())
}
new snippet \/
if result := db.Preload(clause.Associations).Create(&employee); result.Error != nil {
return c.JSON(responseKit.RecordCreateError())
}
Edit
if result := db.Preload(clause.Associations).Find(&employee); result.Error != nil {
return c.JSON(responseKit.RecordCreateError())
}
I have stored procedure in my postgres db
SELECT *FROM get_products()
which returns json
[
{
"id": 1,
"name": "one",
"addition": "spec1",
"size": "",
"category_id": 1,
"vendor_id": 1
},
{
"id": 2,
"name": "two",
"addition": "spec2",
"size": "",
"category_id": 1,
"vendor_id": 1
},
/// ...
]
How could I return the result from the procedure without making a struct, cause there can be unknown numbers of fields in json?
I have this code. It works well, when procedure returns table, but not json
func (s ProductController) GetAll(c *gin.Context) {
db, err := sql.Open("postgres", "host=localhost dbname=postgres sslmode=disable user=postgres")
rows, err := db.Query("SELECT *FROM get_products()")
if err != nil {
panic(err)
}
cols, err := rows.Columns()
if err != nil {
panic(err)
}
allgeneric := make([]map[string]interface{}, 0)
colvals := make([]interface{}, len(cols))
for rows.Next() {
colassoc := make(map[string]interface{}, len(cols))
for i, _ := range colvals {
colvals[i] = new(interface{})
}
if err := rows.Scan(colvals...); err != nil {
panic(err)
}
for i, col := range cols {
colassoc[col] = *colvals[i].(*interface{})
}
allgeneric = append(allgeneric, colassoc)
}
err2 := rows.Close()
if err2 !=nil {
panic(err2)
}
fmt.Println(allgeneric)
c.JSON(200, allgeneric)
}
It returns something like this
[
{
"get_products": "W3siaWQiOjEsIm5hbWUiOiJHMTciLCJhZGRpdGlvbiI6IiIsInNpemUiOiJTdGFuZGFyZCIsImNhdGVnb3J5X2lkIjoxLCJ2ZW5kb3JfaWQiOjF9LCB7ImlkIjoyLCJuYW1lIjoiRzE3IiwiYWRkaXRpb24iOiJHZW40Iiwic2l6ZSI6IlN0YW5kYXJkIiwiY2F0ZWdvcnlfaWQiOjEsInZlbmRvcl9pZCI6MX0sIHsiaWQiOjMsIm5hbWUiOiJHMTciLCJhZGRpdGlvbiI6IkdlbjQgIiwic2l6ZSI6IlN0YW5kYXJkIiwiY2F0ZWdvcnlfaWQiOjEsInZlbmRvcl9pZCI6MX0sIHsiaWQiOjQsIm5hbWUiOiJHMTdDIiwiYWRkaXRpb24iOiJHZW40Iiwic2l6ZSI6IlN0YW5kYXJkIiwiY2F0ZWdvcnlfaWQiOjEsInZlbmRvcl9pZCI6MX0sIHsiaWQiOjUsIm5hbWUiOiJHMTciLCJhZGRpdGlvbiI6IkdlbjUiLCJzaXplIjoiU3
But I need to return json, specified above
UPDATE
modified my code to
func (s ProductController) GetAll(c *gin.Context) {
db, err := sql.Open("postgres", "host=localhost dbname=postgres sslmode=disable user=postgres")
rows, err := db.Query("SELECT *FROM get_products()")
if err != nil {
panic(err)
}
var result []interface{}
cols, _ := rows.Columns()
pointers := make([]interface{}, len(cols))
container := make([]json.RawMessage, len(cols))
for i, _ := range pointers {
pointers[i] = &container[i]
}
for rows.Next() {
rows.Scan(pointers...)
result = append(result, container)
}
fmt.Println(container)
c.JSON(200, container)
}
now it returns
[
[
{
"id": 1,
"name": "one",
"addition": "spec1",
"size": "",
"category_id": 1,
"vendor_id": 1
},
{
"id": 2,
"name": "two",
"addition": "spec2",
"size": "",
"category_id": 1,
"vendor_id": 1
},
]
]
Need to remove this inner array
The query returns a single row with a single column containing the JSON. Use this code to read that single value.
row, err := db.QueryRow("SELECT *FROM get_products()")
if err != nil {
// handle error
}
var jsonData []byte
if err := row.Scan(&jsonData); err != nil {
// handle error
}
c.Data(200, "application/json", jsonData)
There's no need to decode and encode the JSON. Use the JSON data returned form the database as is.
I recommend you this solution for this kind of static queries.
First use .Prepare to create a prepared statement.
db := gopg.Connect(&options)
pgStmt, err := pg.Prepare("SELECT *FROM get_products()")
if err != nil {
log.panic(err)
}
Now, you can simply get the result
var jsonData []byte
_, err := pgStmt.QueryOne(gopg.Scan(&jsonData))
if err != nil {
log.panic(err)
}
c.Data(200, "application/json", jsonData)
You can receive json as string also and then convert it into []byte:
var json string
_, err := pgStmt.QueryOne(gopg.Scan(&json))
if err != nil {
log.panic(err)
}
// do something with that json
jsonData := []byte(json)
c.Data(200, "application/json", jsonData)