show json array inside of a json object using gorm - json

I'm trying to use gorm for my queries. I have a model called users just like this:
type Users struct {
gorm.Model
ID uint `gorm:"autoIncrement;unique" json:"id"`
PhoneNumber string `gorm:"primaryKey" json:"phone_number"`
Name string `gorm:"default:dear user" json:"name"`
Rank uint `json:"rank"`
Score uint `json:"score"`
Image string `json:"image"`
Email string `json:"email"`
Address string `json:"address"`
Birthday string `json:"birthday"`
Biography string `json:"biography"`
}
and another model which represents the courses that the user has purchased.
type UserCourse struct {
CourseID uint `gorm:"primaryKey" json:"course_id"`
UserPhoneNumber string `gorm:"primaryKey" json:"user_phone_number"`
Progress uint `json:"progress"`
CreatedAt time.Time
UpdatedAt time.Time
}
now I am looking for a way to return top 100 users based on their score with the courses they have purchased. in the other word, the below JSON object is desirable:
{
"users":[
{
"id":1,
"phoneNumber":"99999999",
"name":"test",
"rank":1,
"score":123456789,
"image":"http://...",
"email":"test#test.com",
"address":"test",
"birthday":"2021-01-01",
"biography":"test here",
"courses": [
{
"course_id":1,
"user_phone_number":"99999999",
"progress": 53,
"created_at": "2021-01-01",
"updated_at": "2021-01-01",
} ,
{
"course_id":2,
"user_phone_number":"99999999",
"progress":100,
"created_at":"2021-02-01",
"updated_at":"2021-03-01",
}
]
}
]
}
I know I have to use the below query to get top 100 users:
database.myDatabase.Order("rank asc").Limit(100).Find(users)
but unfortunately, I have no idea how to write the gorm suitable for the mentioned output.

If you extend your Users model as such:
type Users struct {
gorm.Model
ID uint `gorm:"autoIncrement;unique" json:"id"`
PhoneNumber string `gorm:"primaryKey" json:"phone_number"`
Name string `gorm:"default:dear user" json:"name"`
Rank uint `json:"rank"`
Score uint `json:"score"`
Image string `json:"image"`
Email string `json:"email"`
Address string `json:"address"`
Birthday string `json:"birthday"`
Biography string `json:"biography"`
Courses []*UserCourse `gorm:"foreignKey:UserPhoneNumber;references:PhoneNumber" json:"courses"`
}
you can then preload the courses into the user struct by using:
database.myDatabase.Preload("Courses").Order("rank asc").Limit(100).Find(users)

Related

Unmarshal a dynamic json

I have a bunch of JSON files that I need to Unmarshal. They have basically the same format, but different "length"
one example
https://pastebin.com/htt6k658
another example
https://pastebin.com/NR1Z08f4
I have tried several methods, like building structs like
type TagType struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
tags []Tag `json:"tags"`
}
type Tag struct {
ID int `json:"users"`
Name string `json:"name"`
Slug string `json:"slug"`
}
also with an interface, like
json.Unmarshal([]byte(empJson), &result)
but none of these methods worked.
The JSON input is an array, so this should work:
var result []TagType
json.Unmarshal(data,&result)
You can use a online tool like https://transform.tools/json-to-go for generating the Go struct:
type AutoGenerated []struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Tags []struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
} `json:"tags"`
}

Receiving unknown response body

I am implementing the Authorize.net credit card API. The API always gives me a 200 response code regardless if the transaction is successful or it is declined. But it gives the one response body for successful transaction and a different one for declined transaction.
type AuthorizeApprovedResponse struct {
TransactionResponse struct {
ResponseCode string `json:"responseCode"`
AuthCode string `json:"authCode"`
AvsResultCode string `json:"avsResultCode"`
CvvResultCode string `json:"cvvResultCode"`
CavvResultCode string `json:"cavvResultCode"`
TransID string `json:"transId"`
RefTransID string `json:"refTransID"`
TransHash string `json:"transHash"`
TestRequest string `json:"testRequest"`
AccountNumber string `json:"accountNumber"`
AccountType string `json:"accountType"`
Messages []struct {
Code string `json:"code"`
Description string `json:"description"`
} `json:"messages"`
UserFields []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"userFields"`
TransHashSha2 string `json:"transHashSha2"`
SupplementalDataQualificationIndicator int `json:"SupplementalDataQualificationIndicator"`
NetworkTransID string `json:"networkTransId"`
} `json:"transactionResponse"`
RefID string `json:"refId"`
Messages struct {
ResultCode string `json:"resultCode"`
Message []struct {
Code string `json:"code"`
Text string `json:"text"`
} `json:"message"`
} `json:"messages"`
}
type AuthorizeDeclinedResponse struct {
TransactionResponse struct {
ResponseCode string `json:"responseCode"`
AuthCode string `json:"authCode"`
AvsResultCode string `json:"avsResultCode"`
CvvResultCode string `json:"cvvResultCode"`
CavvResultCode string `json:"cavvResultCode"`
TransID string `json:"transId"`
RefTransID string `json:"refTransID"`
TransHash string `json:"transHash"`
TestRequest string `json:"testRequest"`
AccountNumber string `json:"accountNumber"`
AccountType string `json:"accountType"`
Errors []struct {
ErrorCode string `json:"errorCode"`
ErrorText string `json:"errorText"`
} `json:"errors"`
UserFields []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"userFields"`
TransHashSha2 string `json:"transHashSha2"`
SupplementalDataQualificationIndicator int `json:"SupplementalDataQualificationIndicator"`
NetworkTransID string `json:"networkTransId"`
} `json:"transactionResponse"`
RefID string `json:"refId"`
Messages struct {
ResultCode string `json:"resultCode"`
Message []struct {
Code string `json:"code"`
Text string `json:"text"`
} `json:"message"`
} `json:"messages"`
}
Here is my problem, which struct to use. I was thinking of trying an interface{} and then try to cast it to a struct?
err := json.Unmarshal(b, &whichStructToUse)
if err != nil {
panic(err.Error())
}
Any advice on how to Unmarshal the response when I don't know which struct to use?
The API always gives me a 200 response code regardless if the transaction is successful or it is declined.
I feel your pain.
There's only one difference between the two responses, success has Messages and failure has Errors. Combine them.
type CommonResponse struct {
TransactionResponse struct {
ResponseCode string `json:"responseCode"`
AuthCode string `json:"authCode"`
AvsResultCode string `json:"avsResultCode"`
CvvResultCode string `json:"cvvResultCode"`
CavvResultCode string `json:"cavvResultCode"`
TransID string `json:"transId"`
RefTransID string `json:"refTransID"`
TransHash string `json:"transHash"`
TestRequest string `json:"testRequest"`
AccountNumber string `json:"accountNumber"`
AccountType string `json:"accountType"`
Messages []struct {
Code string `json:"code"`
Description string `json:"description"`
} `json:"messages"`
Errors []struct {
ErrorCode string `json:"errorCode"`
ErrorText string `json:"errorText"`
} `json:"errors"`
UserFields []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"userFields"`
TransHashSha2 string `json:"transHashSha2"`
SupplementalDataQualificationIndicator int `json:"SupplementalDataQualificationIndicator"`
NetworkTransID string `json:"networkTransId"`
} `json:"transactionResponse"`
RefID string `json:"refId"`
Messages struct {
ResultCode string `json:"resultCode"`
Message []struct {
Code string `json:"code"`
Text string `json:"text"`
} `json:"message"`
} `json:"messages"`
}
Then use that to unmarshall and check for Errors.
var response CommonResponse;
json.Unmarshal([]byte(jsonString), &response)
if len(response.Error) == 0 {
fmt.Println("Success!")
} else {
fmt.Println("Error!")
}
For the more general case, you can unmarshall to a map[string]interface{}.
var result map[string]interface{}
json.Unmarshal([]byte(jsonString), &result)
Demonstration.

How to parse multiple fields into one sub-object in GSON?

I'm trying to parse some json data that looks like this:
{
"store_name": "Coffee Co",
"location": "New York",
"supplier_name": "Cups Corps",
"supplier_id": 12312521,
"supplier_email": "cups#cups.net"
}
And here's my Java POJOs
class Store {
#com.google.gson.annotations.SerializedName("store_name")
String storeName;
String location;
Supplier supplier;
}
class Supplier {
String id;
String name;
String email;
}
//Getters and setters omitted
The issue I'm having is that the fields for the Supplier are flattened directly into the Store record. I tried adding a TypeAdapter to my Gson object for Supplier but it doesn't get triggered because there's no field named supplier on the incoming json object. I also can't use an alternate name for supplier because it needs information from all three of the fields in order to be created.
What is the best way to parse this data so that the nested Supplier field can also be populated?
What you could do is use a custom deserializer:
class StoreDeserializer implements JsonDeserializer<Store> {
#Override
public Store deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonObject jsonObject = jsonElement.getAsJsonObject();
Supplier supplier = new Supplier(
jsonObject.get("supplier_id").getAsInt(),
jsonObject.get("supplier_name").getAsString(),
jsonObject.get("supplier_email").getAsString()
);
return new Store(
jsonObject.get("store_name").getAsString(),
jsonObject.get("location").getAsString(),
supplier
);
}
}
You can then deserialize by registering the deserializer:
String json = "{\"store_name\":\"Coffee Co\",\"location\":\"New York\",\"supplier_name\":\"Cups Corps\",\"supplier_id\":12312521,\"supplier_email\":\"cups#cups.net\"}";
Gson gson = new GsonBuilder().registerTypeAdapter(Store.class, new StoreDeserializer()).create();
Store store = gson.fromJson(json, Store.class);
Note that I changed the type of Supplier#id to int, since it is numeric in your JSON:
class Supplier {
int id;
String name, email;
Supplier(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
}
class Store {
String storeName, location;
Supplier supplier;
Store(String storeName, String location, Supplier supplier) {
this.storeName = storeName;
this.location = location;
this.supplier = supplier;
}
}

Go JSON Naming strategy about extends

My Go struct is like this:
type BaseModel struct {
Id string `json:"id"`
CreatedTime time.Time `json:"createdTime"`
UpdatedTime time.Time `json:"updatedTime"`
Deleted bool `json:"deleted"`
}
type Category struct {
BaseModel
Parent string `json:"parent"`
Name string `json:"name"`
IconClass string `json:"iconClass"`
Mark string `json:"mark"`
}
I want convert Category to JSON like this:
{
"id":"",
"deleted":"",
...
"parent":"",
"name":""
}
But when I use Go's json to convert it, it gives me this:
{
"Id":"",
"Deleted":"",
...
"parent":"",
"name":"",
...
}
What should I do now?
I use under code to convert:
// define
var menus []models.Category
// query from db
q.Filter("deleted__exact", false).All(&menus)
// serialize it
res, _ := json.Marshal(&menus)
s := string(res[:])
beego.Debug(s)
Please, add your convert code here. The code below works fine.
type BaseModel struct {
Id string `json:"id"`
CreatedTime time.Time `json:"createdTime"`
UpdatedTime time.Time `json:"updatedTime"`
Deleted bool `json:"deleted"`
}
type Category struct {
BaseModel
Parent string `json:"parent"`
Name string `json:"name"`
IconClass string `json:"iconClass"`
Mark string `json:"mark"`
}
func main() {
data, err := json.Marshal(Category{})
if err != nil {
return
}
fmt.Println(string(data[:]))
}
Output:
{"id":"","createdTime":"0001-01-01T00:00:00Z","updatedTime":"0001-01-01T00:00:00Z","deleted":false,"parent":"","name":"","iconClass":"","mark":""}

Marshaling []interface{} in Go

type A struct {
Id uint32 `json:"id"`
}
type B struct {
A
Title string `json:"title"`
}
type C struct {
Id uint32 `json:"id"`
Name string `json:"name"`
Arrays []interface{} `json:"arrays"`
}
Is this the correct way to marshal an array of interfaces?
Put arrays in double quotes json:"arrays"