thedevsaddam / gojsonq

A simple Go package to Query over JSON/YAML/XML/CSV Data
https://github.com/thedevsaddam/gojsonq/wiki
MIT License
2.18k stars 140 forks source link

NOT an issue, more a touch of help. Using parameters with gojsonq package #56

Closed JamieW87 closed 5 years ago

JamieW87 commented 5 years ago

I am trying to build a server that can fetch certain json entries based on a parameter. So for example if a user enters localhost:8080/store/1 It returns the json entry with the ID 1.

The code i currently have works if i hardcode the id field into the query, but trying to put in parameters i have so far had no luck. Trying this:

func getGame(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    jq := gojsonq.New().File("./data/games.json")
    res := jq.From("games").Where("id", "=", params["id"]).Get()
    fmt.Println(res)
}

Suggestions please, before i throw something out the window.

Kvaz1r commented 5 years ago

It would be better if you provided full code for reproducing the behaviour. Just using parameter works for me:

package main

import (
    "fmt"
    "math/rand"
    "time"

    "github.com/thedevsaddam/gojsonq"
)

const json = `
{
   "name":"computers",
   "description":"List of computer products",
   "prices":[2400, 2100, 1200, 400.87, 89.90, 150.10],
   "names":["John Doe", "Jane Doe", "Tom", "Jerry", "Nicolas", "Abby"],
   "items":[
      {
         "id":1,
         "name":"MacBook Pro 13 inch retina",
         "price":1350
      },
      {
         "id":2,
         "name":"MacBook Pro 15 inch retina",
         "price":1700
      },
      {
         "id":3,
         "name":"Sony VAIO",
         "price":1200
      },
      {
         "id":4,
         "name":"Fujitsu",
         "price":850
      },
      {
         "id":null,
         "name":"HP core i3 SSD",
         "price":850
      }
   ]
}

`

func main() {
    rand.Seed(time.Now().UnixNano())
    jq := gojsonq.New().JSONString(json).From("items").WhereEqual("id", rand.Intn(5))
    fmt.Printf("%#v\n", jq.Get())
}

go run test.go []interface {}{map[string]interface {}{"price":1200, "id":3, "name":"Sony VAIO"} }

go run test.go []interface {}{map[string]interface {}{"name":"MacBook Pro 15 inch retina", "pri ce":1700, "id":2}}

thedevsaddam commented 5 years ago

I am trying to build a server that can fetch certain json entries based on a parameter. So for example if a user enters localhost:8080/store/1 It returns the json entry with the ID 1.

The code i currently have works if i hardcode the id field into the query, but trying to put in parameters i have so far had no luck. Trying this:

func getGame(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r)
  jq := gojsonq.New().File("./data/games.json")
  res := jq.From("games").Where("id", "=", params["id"]).Get()
  fmt.Println(res)
}

Suggestions please, before i throw something out the window.

It seems the id field is an integer and you are providingparams["id"], which returns id as a string.

Try something like this: Where("id", "=", int(params["id"])) or Where("id", "=", float64(params["id"]))

If not working, provide more information/source code/data structure.

Kvaz1r commented 5 years ago

Try convert this way:

    i, _ := strconv.Atoi(params["id"])
    res := jq.From("games").WhereEqual("id", i).Get()
JamieW87 commented 5 years ago

Using Atoi worked a treat. Thank you for pointing me in the right direction.

My question now has a second phase if you dont mind. It now prints out the json as the screenshot below. What do i need to use to print it out as per the structs?

Screenshot 2019-07-04 at 16 32 27

games.go:

package models

type Games struct {
    Games    []Game    `json:"games"`
    Comments []Comment `json:"comments"`
}

type Comment struct {
    User        string `json:"user"`
    Message     string `json:"message"`
    DateCreated string `json:"dateCreated"`
    Like        int    `json:"like"`
}

type Game struct {
    ID          int     `json:"id"`
    Title       string  `json:"title"`
    Description string  `json:"description"`
    By          string  `json:"by"`
    Platform    string  `json:"platform"`
    AgeRating   string  `json:"age_rating"`
    Likes       int     `json:"likes"`
    Comment     Comment `json:"comments"`
}

games.json

"games":[
    {"id": 1,
    "title": "Uncharted 4",
    "description": "For the first time ever in Uncharted history, drive vehicles during gameplay",
    "by": "Sony",
    "platform": ["PS4"],
    "age_rating": "16",
    "likes": 100,
    "comments": [{
        "user": "bob",
        "message": "Cracking game far too much cinematic",
        "dateCreated": "2011-01-03",
        "like": 6
    }, {
        "user": "testingPriest",
        "message": "Not enough shooting for me,far too easy ",
        "dateCreated": "2011-04-02",
        "like": 5
        }]
    },
Kvaz1r commented 5 years ago

Define corresponding method (String/0) for your structs. From the documentation:

Except when printed using the verbs %T and %p, special formatting considerations apply for operands that implement certain interfaces. In order of application:

  1. If the operand is a reflect.Value, the operand is replaced by the concrete value that it holds, and printing continues with the next rule.

  2. If an operand implements the Formatter interface, it will be invoked. Formatter provides fine control of formatting.

  3. If the %v verb is used with the # flag (%#v) and the operand implements the GoStringer interface, that will be invoked.

If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:

  1. If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).

  2. If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).

JamieW87 commented 5 years ago

Sorry i'm showing my inexperience here but how do i do that? I want to return the json as it appears in the json file. Ive tried unmarshalling it etc but that doesnt seem to work with this package.

Kvaz1r commented 5 years ago

Ahh, it's seems I didn't understand what format you want to get. Well you can use method Writer to write result to any io.Writer in json format. If my assumptions still wrong it would be better provide format which do you want to see. I mean exactly content of file or something like that :)

JamieW87 commented 5 years ago

Thank you for your help so far. It seems you have it write this time. I want the json to show in the browser the same way it shows in the json file itself. Like this for example:

Screenshot 2019-07-04 at 21 27 51

JamieW87 commented 5 years ago

Having a play, Ive now managed to get this output, using MarshalIndent. But the keys are not in the right order, they dont match the order of the original json file above:

Screenshot 2019-07-04 at 21 55 35

Here is the code of the function now

func getGame(w http.ResponseWriter, r *http.Request) {
    //Open the json file
    jq := gojsonq.New().File("./data/games.json")
    params := mux.Vars(r)
    //Convert the param string to an int to match the json and so it can be used in the query
    idTwo, _ := strconv.Atoi(params["id"])
    //Query the json to print out the parameter from the url
    res := jq.From("games").Where("id", "=", idTwo).Get()
    //json.NewEncoder(w).Encode(res)
    //Prints to the console
    fmt.Println(res)
    //Prints to browser
    b, _ := json.MarshalIndent(res, "", "")
    w.Write(b)
}