{"id":23209380,"url":"https://github.com/metalim/jsonmap","last_synced_at":"2025-08-03T01:13:31.300Z","repository":{"id":171745340,"uuid":"646977436","full_name":"metalim/jsonmap","owner":"metalim","description":"Ordered map for JSON storage","archived":false,"fork":false,"pushed_at":"2024-07-14T09:34:20.000Z","size":60,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-14T10:45:10.473Z","etag":null,"topics":["go","golang","json","orderedmap"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metalim.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-29T19:31:53.000Z","updated_at":"2024-07-14T09:34:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"4b04f9b5-8c5e-4d15-bd72-afd4180a0e5a","html_url":"https://github.com/metalim/jsonmap","commit_stats":null,"previous_names":["metalim/jsonmap"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalim%2Fjsonmap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalim%2Fjsonmap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalim%2Fjsonmap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalim%2Fjsonmap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metalim","download_url":"https://codeload.github.com/metalim/jsonmap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230318609,"owners_count":18207813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","json","orderedmap"],"created_at":"2024-12-18T18:16:50.454Z","updated_at":"2024-12-18T18:16:51.109Z","avatar_url":"https://github.com/metalim.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ordered map\n\n[![go test workflow](https://github.com/metalim/jsonmap/actions/workflows/gotest.yml/badge.svg)](https://github.com/metalim/jsonmap/actions/workflows/gotest.yml)\n[![go report](https://goreportcard.com/badge/github.com/metalim/jsonmap)](https://goreportcard.com/report/github.com/metalim/jsonmap)\n[![codecov](https://codecov.io/gh/metalim/jsonmap/graph/badge.svg?token=HLGJ7U07JH)](https://codecov.io/gh/metalim/jsonmap)\n[![go doc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/metalim/jsonmap)\n[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/mit/)\n\nSimple ordered map for Go, with JSON restrictions. The main purpose is to keep same order of keys after parsing JSON and generating it again, so Unmarshal followed by Marshal generates exactly the same JSON structure\n\nKeys are strings, Values are any JSON values (number, string, boolean, null, array, map/object)\n\nStorage is O(n), operations are O(1), except for optional operations in [slow.go](slow.go) file\n\nWhen Unmarshalling, **any nested map from JSON is created as ordered jsonmap**, including maps in nested arrays\n\nInspired by [wk8/go-ordered-map](https://github.com/wk8/go-ordered-map) and [iancoleman/orderedmap](https://github.com/iancoleman/orderedmap)\n\n## Performance\n\nSimilar to Go native map, `jsonmap` has O(1) time for Get, Set, Delete. Additionally it has Push, First, Last, Next, Prev operations, which are also O(1). Suite benchmark does 10k of Set and Get, and 1k of Delete operations. `jsonmap` performance is on par with native Go map\n\n```\n➜ go test -bench . -benchmem ./test\ngoos: darwin\ngoarch: arm64\npkg: github.com/metalim/jsonmap/test\nBenchmark/Suite/jsonmap-10            36          31614692 ns/op        17046302 B/op     623006 allocs/op\nBenchmark/Suite/gomap-10              48          25116164 ns/op        14791564 B/op     522925 allocs/op\nBenchmark/Ops/Get/jsonmap-10            11191284               112.3 ns/op             0 B/op          0 allocs/op\nBenchmark/Ops/Get/gomap-10              11543529                97.88 ns/op            0 B/op          0 allocs/op\nBenchmark/Ops/SetExisting/jsonmap-10     5847512               291.3 ns/op           106 B/op          1 allocs/op\nBenchmark/Ops/SetExisting/gomap-10       7608140               174.6 ns/op            89 B/op          1 allocs/op\nBenchmark/Ops/SetNew/jsonmap-10          2548009               429.3 ns/op           242 B/op          2 allocs/op\nBenchmark/Ops/SetNew/gomap-10            5143821               212.3 ns/op           133 B/op          1 allocs/op\nBenchmark/Ops/Delete/jsonmap-10          7642382               156.0 ns/op             0 B/op          0 allocs/op\nBenchmark/Ops/Delete/gomap-10           10592187               102.4 ns/op             0 B/op          0 allocs/op\nPASS\nok      github.com/metalim/jsonmap/test 143.577s\n```\n\n## Installation\n```bash\n$ go get github.com/metalim/jsonmap\n```\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/metalim/jsonmap\"\n)\n\nconst sampleJSON = `{\"an\":\"article\",\"empty\":null,\"sub\":{\"s\":1,\"e\":2,\"x\":3,\"y\":4},\"bool\":false,\"array\":[1,2,3]}`\n\nfunc main() {\n\tm := jsonmap.New()\n\n\t// unmarshal, keeping order\n\terr := json.Unmarshal([]byte(sampleJSON), \u0026m)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// get values\n\tval, ok := m.Get(\"an\")\n\tfmt.Println(\"an: \", val, ok) // article true\n\tval, ok = m.Get(\"non-existant\")\n\tfmt.Println(\"non-existant\", val, ok) // \u003cnil\u003e false\n\n\t// marshal, keeping order\n\toutput, err := json.Marshal(\u0026m)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tif string(output) == sampleJSON {\n\t\tfmt.Println(\"output == sampleJSON\")\n\t}\n\n\t// iterate\n\tfmt.Println(\"forward order:\")\n\tfor el := m.First(); el != nil; el = el.Next() {\n\t\tfmt.Printf(\"\\t%s: %v\\n\", el.Key(), el.Value())\n\t}\n\tfmt.Println()\n\n\tfmt.Println(\"backwards order:\")\n\tfor el := m.Last(); el != nil; el = el.Prev() {\n\t\tfmt.Printf(\"\\t%s: %v\\n\", el.Key(), el.Value())\n\t}\n\tfmt.Println()\n\n\tfmt.Println(`forward from key \"sub\":`)\n\tfor el := m.GetElement(\"sub\"); el != nil; el = el.Next() {\n\t\tfmt.Printf(\"\\t%s: %v\\n\", el.Key(), el.Value())\n\t}\n\tfmt.Println()\n\n\t// print map\n\tfmt.Println(m) // map[an:article empty:\u003cnil\u003e sub:map[s:1 e:2 x:3 y:4] bool:false array:[1 2 3]]\n\n\t// set new values, keeping order of existing keys\n\tm.Set(\"an\", \"bar\")\n\tm.Set(\"truth\", true)\n\tfmt.Println(m) // map[an:bar empty:\u003cnil\u003e sub:map[s:1 e:2 x:3 y:4] bool:false array:[1 2 3] truth:true]\n\n\t// delete key \"sub\"\n\tm.Delete(\"sub\")\n\tfmt.Println(m) // map[an:bar empty:\u003cnil\u003e bool:false array:[1 2 3] truth:true]\n\n\t// update value for key \"an\", and move it to the end\n\tm.Push(\"an\", \"end\")\n\tfmt.Println(m) // map[empty:\u003cnil\u003e bool:false array:[1 2 3] truth:true an:end]\n\n\tdata, err := json.Marshal(\u0026m)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(string(data)) // {\"empty\":null,\"bool\":false,\"array\":[1,2,3],\"truth\":true,\"an\":\"end\"}\n}\n\n```\n\n## Alternatives\n\n* [iancoleman/orderedmap](https://github.com/iancoleman/orderedmap) — has O(n) time for Delete\n* [wk8/go-ordered-map](https://github.com/wk8/go-ordered-map) — Unmarshal creates nested maps as native unordered maps, which makes it useless for my purposes\n\nLet me know of other alternatives, I'll add them here\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetalim%2Fjsonmap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetalim%2Fjsonmap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetalim%2Fjsonmap/lists"}