What i am trying to do is to load an whole object coming from my database into an object.
type RatingPK struct {
ratingsPK Rating
}
func (r *RatingPK) Init(rg Rating) {
r.ratingsPK = rg
}
func searchUserRatings(id string)(ratings []Rating) {
rows, err := db.Query("SELECT * FROM ratings WHERE userId = ?", id)
if err != nil {
return
}
for rows.Next() {
rate := Rating{}
err = rows.Scan(&rate.MovieId, &rate.UserId, &rate.RatingId, &rate.Rating, &rate.Timestamp)
if err != nil {
return
}
r := RatingPK{}
r.Init(rate)
ratings = append(ratings, r)
}
defer rows.Close()
return
}
this code gives me this result:
[{
"rating_id": 593,
"userId": 2,
"movieId": 93,
"rating": 3,
"timestamp": "0000-00-00"
},
{
"rating_id": 616,
"userId": 2,
"movieId": 94,
"rating": 3,
"timestamp": "0000-00-00"
}]
Now what i want to do is to get each object of the array and put in to another object and the desired result will be this:
[{"ratingsPK": {
"rating_id": 593,
"userId": 2,
"movieId": 93,
"rating": 3,
"timestamp": "0000-00-00"
}},
{"ratingsPK": {
"rating_id": 616,
"userId": 2,
"movieId": 94,
"rating": 3,
"timestamp": "0000-00-00"
}}]
Is there any way to achieve that?
You may loop and do as follows
type RatingPK struct {
ratingsPK Rating
}
func (r *RatingPK) Init(rg Rating) {
r.ratingsPK = rg
}
func searchUserRatings(id string) (ratings []RatingPK) {
rows, err := db.Query("SELECT * FROM ratings WHERE userId = ?", id)
if err != nil {
return
}
var myarray []string
for rows.Next() {
rate := Rating{}
err = rows.Scan(&rate.MovieId, &rate.UserId, &rate.RatingId, &rate.Rating, &rate.Timestamp)
if err != nil {
return
}
r := RatingPK{}
r.Init(rate)
ratings = append(ratings, r)
}
defer rows.Close()
return
}
Here's a short example that will help you understand how to use nested structs ;)
package main
import (
"fmt"
)
type nameType struct {
firstName string
lastName string
}
type student struct {
name nameType
age int
}
func main() {
bob := student{nameType{"bob", "dope"}, 18}
fmt.Println(bob.name.firstName)
}
You can test it up here ;)
https://play.golang.org/p/ft9PGrlrrx
Related
I have an array of objects that I would like to use to create a new slice while grouping a field for objects with the same id(the id, in this case, the id is pay_method_id) into an array of objects. i.e I want to group all users with a particular payment method
sample input
[{
"user_id": 1,
"pay_method_id": 1
}
{
"user_id": 2,
"pay_method_id": 2
}
{
"user_id": 4,
"pay_method_id": 1
}
{
"user_id": 3,
"pay_method_id": 2
}]
expected output
[
{"pay_method_id" : "2",
"users": [{"user_id": 2}, {"user_id": 3}]
}
{
"pay_method_id" : "1",
"users": [{"user_id": 4}, {"user_id": 1}]
}
]
Struct representing input
type paymenthodUsers struct{
PayMethodID int
UserID int
}
Struct for the output
type paymentMethodGrouped struct{
PayMethodID int
Users []user
}
type user struct{
UserID int
}
How do I generate the expected output above in golang?
package main
import (
"encoding/json"
"fmt"
"log"
)
type paymenthodUsers struct {
PayMethodID int `json:"pay_method_id"`
UserID int `json:"user_id"`
}
type paymentMethodGrouped struct {
PayMethodID int `json:"pay_method_id"`
Users []user `json:"users"`
}
type user struct {
UserID int `json:"user_id"`
}
func main() {
_json := `[{
"user_id": 1,
"pay_method_id": 1
},
{
"user_id": 2,
"pay_method_id": 2
},
{
"user_id": 4,
"pay_method_id": 1
},
{
"user_id": 3,
"pay_method_id": 2
}]`
var paymentmethods []paymenthodUsers
err := json.Unmarshal([]byte(_json), &paymentmethods)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Original input : %+v\n", paymentmethods)
groups := make(map[int][]user)
for _, pm := range paymentmethods {
if _, found := groups[pm.PayMethodID]; !found {
groups[pm.PayMethodID] = []user{}
}
groups[pm.PayMethodID] = append(groups[pm.PayMethodID], user{pm.UserID})
}
paymentGroups := []paymentMethodGrouped{}
for k, v := range groups {
paymentGroups = append(paymentGroups, paymentMethodGrouped{k, v})
}
data, err := json.Marshal(paymentGroups)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Grouped: %s", string(data))
}
Go Playground Demo
i want to get all keys and values of json fields as type map[string][]string. The objects with same keys, should be in same map field.
I can convert JSON to map[string]interface{} now with this function, but it doesn't meet my needs.
func jsonToMap(data []byte) map[string]interface{} {
x := map[string]interface{}
json.Unmarshal(data, &x)
return x
}
Sample json:
{
"data": {
"name": "John",
"age": 30
},
"items": [
1,
2,
3
],
"data2": {
"name": "Johns",
"age": {
"test": [
1,
2,
3,
{
"test2": "123"
}
]
}
}
}
Expected result:
map[string][]string
map["data"][]string{""}
map["name"][]string{"John", "Johns"}
map["age"][]string{"30",""}
map["items"][]string{"1","2","3"}
map["test"][]string{"1","2","3"}
map["test2"][]string{"123"}
The solution is using recursive function.
https://en.wikipedia.org/wiki/Recursion_(computer_science)
Here is a simple example:
https://gobyexample.com/recursion
The following code can do what you want:
package main
import (
"encoding/json"
"fmt"
)
func main() {
JSONStr := `{
"data": {"name": "John", "age": 30},
"items": [1, 2, 3],
"data2": {
"name": "Johns",
"age": {"test": [1, 2, 3, {"test2": "123"}]}
}
}`
var JSON map[string]interface{}
json.Unmarshal([]byte(JSONStr), &JSON)
neededOutput := jsonToMap(JSON)
fmt.Println(neededOutput)
}
func jsonToMap(data map[string]interface{}) map[string][]string {
// final output
out := make(map[string][]string)
// check all keys in data
for key, value := range data {
// check if key not exist in out variable, add it
if _, ok := out[key]; !ok {
out[key] = []string{}
}
if valueA, ok := value.(map[string]interface{}); ok { // if value is map
out[key] = append(out[key], "")
for keyB, valueB := range jsonToMap(valueA) {
if _, ok := out[keyB]; !ok {
out[keyB] = []string{}
}
out[keyB] = append(out[keyB], valueB...)
}
} else if valueA, ok := value.([]interface{}); ok { // if value is array
for _, valueB := range valueA {
if valueC, ok := valueB.(map[string]interface{}); ok {
for keyD, valueD := range jsonToMap(valueC) {
if _, ok := out[keyD]; !ok {
out[keyD] = []string{}
}
out[keyD] = append(out[keyD], valueD...)
}
} else {
out[key] = append(out[key], fmt.Sprintf("%v", valueB))
}
}
} else { // if string and numbers and other ...
out[key] = append(out[key], fmt.Sprintf("%v", value))
}
}
return out
}
Output:
map[age:[30 ] data:[] data2:[] items:[1 2 3] name:[John Johns] test:[1 2 3] test2:[123]]
I have the following json data coming through an API. I want to unmarshal this data into a different way of structure as it is defined below. How can I do it in an elegant way?
{
"_meta": {
"count": 2,
"total": 2
},
"0": {
"key": "key0",
"name": "name0"
},
"1": {
"key": "key1",
"name": "name1"
},
"2": {
"key": "key2",
"name": "name2"
}
// It goes on..
}
type Data struct {
Meta Meta `json:"_meta,omitempty"`
Elements []Element
}
type Element struct {
Key string
Name string
}
type Meta struct{
Count int
Total int
}
This can be quite tricky because you have a json object that holds everything. So i went with the approach of unmarshalling to map of string to *json.RawMessage and then fixing the struct from there.
To do that you will be using a custom Unmarshaler and the benefit of it is that you delay the actual parsing of the inner messages until you need them.
So for example if your meta field was wrong or the numbers it said didn't match the length of the map-1 you could exit prematurely.
package main
import (
"encoding/json"
"fmt"
)
type jdata map[string]*json.RawMessage
type data struct {
Meta Meta
Elements []Element
}
//Element is a key val assoc
type Element struct {
Key string
Name string
}
//Meta holds counts and total of elems
type Meta struct {
Count int
Total int
}
var datain = []byte(`
{
"_meta": {
"count": 2,
"total": 2
},
"0": {
"key": "key0",
"name": "name0"
},
"1": {
"key": "key1",
"name": "name1"
},
"2": {
"key": "key2",
"name": "name2"
}
}`)
func (d *data) UnmarshalJSON(buf []byte) (err error) {
var (
meta *json.RawMessage
ok bool
)
jdata := new(jdata)
if err = json.Unmarshal(buf, jdata); err != nil {
return
}
if meta, ok = (*jdata)["_meta"]; !ok {
return fmt.Errorf("_meta field not found in JSON")
}
if err = json.Unmarshal(*meta, &d.Meta); err != nil {
return
}
for k, v := range *jdata {
if k == "_meta" {
continue
}
elem := &Element{}
if err = json.Unmarshal(*v, elem); err != nil {
return err
}
d.Elements = append(d.Elements, *elem)
}
return nil
}
func main() {
data := &data{}
if err := data.UnmarshalJSON(datain); err != nil {
panic(err)
}
fmt.Printf("decoded:%v\n", data)
}
Could you help me to understand why I'm always getting the error unexpected end of JSON input while trying to unmarshal the following json to the LimitOrder struct?
P.S.: if I use map[string]json.RawMessage instead of LimitOrder struct I'm able to execute the unmarshal.
{
"response_data": {
"order": {
"order_id": 3,
"coin_pair": "BRLBTC",
"order_type": 1,
"status": 4,
"has_fills": true,
"quantity": "1.00000000",
"limit_price": "900.00000",
"executed_quantity": "1.00000000",
"executed_price_avg": "900.00000",
"fee": "0.00300000",
"created_timestamp": "1453835329",
"updated_timestamp": "1453835329",
"operations": [
{
"operation_id": 1,
"quantity": "1.00000000",
"price": "900.00000",
"fee_rate": "0.30",
"executed_timestamp": "1453835329"
}
]
}
},
"status_code": 100,
"server_unix_timestamp": "1453835329"
}
LimitOrder struct
type LimitOrder struct {
OrderId int `json:"order_id"`
CoinPair string `json:"coin_pair"`
OrderType int `json:"order_type"`
Status int `json:"status"`
HasFills bool `json:"has_fills"`
Quantity float64 `json:"quantity,string"`
LimitPrice float64 `json:"limit_price,string"`
ExecutedQuantity float64 `json:"executed_quantity,string"`
ExecutedPriceAvg float64 `json:"executed_price_avg,string"`
Fee float64 `json:"fee,string"`
Operations []*Operation `json:"operations"`
CreatedTimestamp string `json:"created_timestamp"`
UpdatedTimestamp string `json:"updated_timestamp"`
}
and this is how I'm trying to unmarshal it
func (limitOrder *LimitOrder) UnmarshalJSON(buf []byte) error {
tmp := make(map[string]json.RawMessage)
if err := json.Unmarshal(buf, &tmp); err != nil {
return err
}
tmp2 := make(map[string]json.RawMessage)
if err := json.Unmarshal(tmp["response_data"], &tmp2); err != nil {
return err
}
if err := json.Unmarshal(tmp2["order"], limitOrder); err != nil {
return err
}
return nil
}
I found some help on golang-nuts group. You can check the answer here https://groups.google.com/forum/#!topic/golang-nuts/SZXBcXgUoo0. To make a long story short, the problem was with my structures, I've built structures only for a small piece of the whole json, so I fixed it building structures for the whole json response.
Currently, I am learning hyperledger/fabric and trying to write the chaincode. Below is the invoke function and customized function I created.
type Donation struct {
Id string `json:"id"`
Who string `json:"who"`
Rid string `json:"rid"`
Money int `json:"money"`
}
type Request struct {
Id string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
ExpectedMoney int `json:"expectedMoney"`
CurrentMoney int `json:"currentMoney"`
DonationList []string `json:"donationList"`
}
type Person struct {
Id string `json:"id"`
Name string `json:"name"`
MyRequests []string `json:"myRequests"`
MyDonations []string `json:"myDonations"`
}
func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
if function == "createDonation" {
return t.createDonation(stub, args)
}
return nil, errors.New("Received unknown function invocation")
}
func (t *SimpleChaincode) createDonation(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
var from, toRid string
var money int
var err error
if len(args) != 3 {
return nil, errors.New("My createDonation. Incorrect number of arguments. Expecting 3")
}
from = args[0]
toRid = args[1]
money, err = strconv.Atoi(args[2])
if err != nil {
return nil, errors.New("money cannot convert to number")
}
var donation Donation
donation = Donation{Id: "donationid", Rid: toRid, Who: from, Money: money}
djson, err := json.Marshal(&donation)
if err != nil {
return nil, err
}
var a = donation.Id
stub.PutState(a, djson)
personByte, err := stub.GetState(from + "")
fmt.Println(personByte)
return nil, nil
}
func (t *SimpleChaincode) read(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
log.Println("Get into read function")
var key, jsonResp string
var err error
key = args[0]
valAsbytes, err := stub.GetState(key)
if err != nil {
jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}"
return nil, errors.New(jsonResp)
}
if valAsbytes == nil {
return []byte("cannot find the key's value of the chaincode"), nil
}
return valAsbytes, nil
}
However, When I tried to use swagger UI to invoke and retrieve the "donationid"'s value, it is empty. Is there anything wrong about my code? Thanks in advance.
Invoke
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID": {
"name": "92d975f9301f9b72c7b148e65dcc835a971be55b2555a45c41d6d2eed04ecfd6b1974245cfb77d002e244e9e581e4042747e9f4d6a46b59e9d7e8a7419476296"
},
"ctorMsg": {
"function": "createDonation",
"args": [
"Simon",
"requestid",
"300"
]
},
"secureContext": "user_type1_XXXXXXX"
},
"id": 3
}
query
{
"jsonrpc": "2.0",
"method": "query",
"params": {
"type": 1,
"chaincodeID": {
"name": "92d975f9301f9b72c7b148e65dcc835a971be55b2555a45c41d6d2eed04ecfd6b1974245cfb77d002e244e9e581e4042747e9f4d6a46b59e9d7e8a7419476296"
},
"ctorMsg": {
"function": "read",
"args": [
"donationid"
]
},
"secureContext": "user_type1_xxxxxx"
},
"id": 2
}