gjson icon indicating copy to clipboard operation
gjson copied to clipboard

Support "@unique" modifier

Open Altenrion opened this issue 2 years ago • 1 comments

I understand that this modifier can be easily done by anyone, but suppose that it migth be needed not only by me and it would be clearer to use from lib.

I suggest to add modifier @unique , if it would be not so hard.

gjson.AddModifier("unique", func(_json, arg string) string {
		var arr []string
		_ = json.Unmarshal([]byte(_json), &arr)

		keys := make(map[string]bool)
		var list []string

		for _, entry := range arr {
			if _, value := keys[entry]; !value {
				keys[entry] = true
				list = append(list, entry)
			}
		}
		data, _ := json.Marshal(list)
		return string(data)
	})

I Understand that there might be a lot of different cases , not only flat slice of strings.

I needed to extract uniq user_ids and count them, so I would provide my case here as example:

json_bytes := []byte(`{
  "agreements": [
    {"a_id":"1111", "policies":[
		{"id":"1", "insured_id":"123"},
		{"id":"2", "insured_id":"222"},
		{"id":"3", "insured_id":"333"},
	]},
	{"a_id":"2222", "policies":[
		{"id":"4", "insured_id":"444"},
		{"id":"5", "insured_id":"222"},
		{"id":"6", "insured_id":"666"},
	]},
  ]
}`)

	gjson.AddModifier("unique", func(_json, arg string) string {
		var arr []string
		_ = json.Unmarshal([]byte(_json), &arr)

		keys := make(map[string]bool)
		var list []string

		for _, entry := range arr {
			if _, value := keys[entry]; !value {
				keys[entry] = true
				list = append(list, entry)
			}
		}
		data, _ := json.Marshal(list)
		return string(data)
	})

	value := gjson.Get(string(json_bytes), "agreements.#.policies.#.insured_id|@flatten|@unique.#")
	println("result:",value.String())
result: 5

can discuss here and i can prepare PR

Altenrion avatar Sep 04 '21 07:09 Altenrion

Unique is useful, but i don't think that you need to unmarshal json, you can parse it with gjson, will be faster

hotrush avatar Mar 02 '22 16:03 hotrush