valyala / fastjson

Fast JSON parser and validator for Go. No custom structs, no code generation, no reflection
MIT License
2.3k stars 138 forks source link

How to construct nested JSON using for loops and arenapools? #69

Open clarencefoy opened 3 years ago

clarencefoy commented 3 years ago

Hi, I am currently having to construct a JSON file containing three things. Instances, versions and function names.

Each instance has a version, each version has multiple function names.

Therefore, each 'version' is an array. Each 'instance' has multiple versions.

In pseudocode, I would append each 'function name' to an array (which will be 'version'), and then I would set a key within 'instance' to the 'version', which holds this array of 'function name'.

The problem is that I can't for the life of me figure out how to use the ArenaPool approach to make this safe. It would appear I am always ending up with the 'version' array containing the entries of the last for loop that has been iterated through.

See the following code:


    instances := []Stat{}
    versions := []Stat{}
    functions := []Stat{}
    var ap fastjson.ArenaPool
    are := ap.Get()
    verJSON := are.NewObject()
    instJSON := are.NewObject()

    err := sts.db.Select(&instances, "select distinct on (instance) instance from stats")
    if err != nil {
        [handle error]
        return nil, err
    }

    for _, inst := range instances {
        err := sts.db.Select(&versions, "select distinct on (version) version from stats WHERE instance = $1", inst.Instance)
        if err != nil {
            [handle error]
            return nil, err
        }
        for _, ver := range versions {
            err := sts.db.Select(&functions, "select distinct on (func_name) func_name from stats where instance = $1 and version = $2", inst.Instance, ver.Version)
            if err != nil {
                [handle error]
                return nil, err
            }
            newAr := ap.Get()
            defer ap.Put(newAr)
            arr := newAr.NewArray()
            for i, fun := range functions {
                arr.SetArrayItem(i, newAr.NewString(fun.FuncName))
            }
            verJSON.Set(ver.Version, arr)
            functions = nil
            instJSON.Set(inst.Instance, verJSON)
        }
        versions = nil
    }

    fmt.Println("This is instJSON: ", instJSON)

'instJSON' always ends up containing the 'verJSON' from the second to last and last loop of 'range instances'.