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)
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 have sumfile.json that needs to be quoted into specific format.
{
"address": "312312321321",
"number": "d56"
"type": "chocolate",
"model": "dcdas55A",
"partnumber": "adasdasA",
...
and i have to make it look like this:
"data": "{\"address\": null, \"number\": \"-DI1\", \"_type\": \"\", \"model\": \"CI STO\", \"number\": \"603sjhhd2\",
Just read the file into a byte slice, convert the bytes into a string, and then marshal the string as JSON.
f, err := os.Open("sumfile.json")
if err != nil {
panic(err)
}
defer f.Close()
raw, err := io.ReadAll(f)
if err != nil {
panic(err)
}
out, err := json.Marshal(map[string]string{"data": string(raw)})
if err != nil {
panic(err)
}
fmt.Println(string(out))
https://go.dev/play/p/0lCwHLC8Tno
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.
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 JSON like
{
"a": {"key": "a", "value": 1,},
"b": {"key": "b", "value": 1,},
}
Is there a way to unmarshal it into []*struct {Key string; Value int}, preserving the order of the structures?
If I unmarshal the JSON into map[string]*struct {Key string; Value int} and then convert the map into a slice, I'll lose the order of the structures.
To preserve order, use Decoder.Token and Decoder.More to walk through the top-level JSON object.
r := strings.NewReader(`
{
"a": {"key": "a", "value": 1},
"b": {"key": "b", "value": 1}
}`)
d := json.NewDecoder(r)
t, err := d.Token()
if err != nil || t != json.Delim('{') {
log.Fatal("expected object")
}
var result []*element
for d.More() {
k, err := d.Token()
if err != nil {
log.Fatal(err)
}
var v element
if err := d.Decode(&v); err != nil {
log.Fatal(err)
}
result = append(result, &v)
fmt.Println("key:", k, "value:", v)
}
Run it on the Go Playground
Change the calls to log.Fatal to the error handling appropriate for your application.
This answer edits the JSON in the question to make the JSON valid.
The field names in the struct element type must be exported.
The easiest way that I found was to use jsonparser.ObjectEach:
import "github.com/buger/jsonparser"
...
var ss []*struct{Key string; Value int}
err = jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
var s struct{Key string; Value int}
if err := json.Unmarshal(value, &s); err != nil {
return err
}
*ss = append(*ss, &s)
return nil
})
You could use the map[string]interface{} to unmarshal the json string.
The code is this
func test() {
jsonStr := `
{
"a": {"key": "a", "value": 1},
"b": {"key": "b", "value": 1}
}`
var mapResult map[string]interface{}
err := json.Unmarshal([]byte(jsonStr), &mapResult)
if err != nil {
fmt.Println("JsonToMapDemo err: ", err)
}
fmt.Println(mapResult)
}
the output is:
map[a:map[key:a value:1] b:map[key:b value:1]]