{"action":"created","issue":{"url":"https://api.github.com/repos/buger/jsonparser/issues/58","repository_url":"https://api.github.com/repos/buger/jsonparser","labels_url":"https://api.github.com/repos/buger/jsonparser/issues/58/labels{/name}","comments_url":"https://api.github.com/repos/buger/jsonparser/issues/58/comments","events_url":"https://api.github.com/repos/buger/jsonparser/issues/58/events","html_url":"https://github.com/buger/jsonparser/pull/58","id":166962557,"number":58,"title":"Add ObjectEach() for iterating over object key-value pairs","user":{"login":"daboyuka","id":3924734,"avatar_url":"https://avatars.githubusercontent.com/u/3924734?v=3","gravatar_id":"","url":"https://api.github.com/users/daboyuka","html_url":"https://github.com/daboyuka","followers_url":"https://api.github.com/users/daboyuka/followers","following_url":"https://api.github.com/users/daboyuka/following{/other_user}","gists_url":"https://api.github.com/users/daboyuka/gists{/gist_id}","starred_url":"https://api.github.com/users/daboyuka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daboyuka/subscriptions","organizations_url":"https://api.github.com/users/daboyuka/orgs","repos_url":"https://api.github.com/users/daboyuka/repos","events_url":"https://api.github.com/users/daboyuka/events{/privacy}","received_events_url":"https://api.github.com/users/daboyuka/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":19,"created_at":"2016-07-22T03:16:28Z","updated_at":"2016-08-26T13:16:22Z","closed_at":"2016-08-26T11:52:38Z","pull_request":{"url":"https://api.github.com/repos/buger/jsonparser/pulls/58","html_url":"https://github.com/buger/jsonparser/pull/58","diff_url":"https://github.com/buger/jsonparser/pull/58.diff","patch_url":"https://github.com/buger/jsonparser/pull/58.patch"},"body":"This PR implements the `ObjectEach` function to iterate over the key-value pairs of a JSON object. Its signature is as follows:\r\n\r\n```\r\nObjectEach(\r\n  data []byte,\r\n  callback func(key []byte, value []byte, valueType ValueType, offset int) error,\r\n)\r\n```\r\n\r\n`ObjectEach` will invoke `callback` for each key-value pair in the JSON object contained in `data` as follows:\r\n* `key` will be the _unescaped_ key string of the key-value pair\r\n* `value` will be the raw bytes composing the value of the key-value pair (as if returned by `Get()`; quotes are stripped from strings, `null` is represented as an empty byte slice, and all other values are passed as their literal bytes)\r\n* `valueType` is the JSON data type of `value`\r\n* `offset` is the byte offset just past the end of the value of the key-value pair\r\n\r\nIf any invocation of `callback` returns a non-nil error, the iteration terminates and that error is returned from `ObjectEach` itself.\r\n\r\nThe name `ObjectEach` was chosen to mirror the analogous `ArrayEach`, which iterates over the elements of a JSON array with a callback.\r\n\r\nRelevant benchmarks:\r\n```\r\n$ goapp test -bench \"BenchmarkJsonParser.*Struct.*\" -benchtime 10s -benchmem\r\nBenchmarkJsonParserEachKeyStructMedium-8   \t 1000000\t     15307 ns/op\t     544 B/op\t      11 allocs/op\r\nBenchmarkJsonParserObjectEachStructMedium-8\t  500000\t     23988 ns/op\t     608 B/op\t      12 allocs/op\r\nBenchmarkJsonParserEachKeyStructSmall-8    \t10000000\t      2248 ns/op\t     176 B/op\t       7 allocs/op\r\nBenchmarkJsonParserObjectEachStructSmall-8 \t10000000\t      2129 ns/op\t     240 B/op\t       8 allocs/op\r\n```\r\n\r\nThe decreased performance seen on the `Medium` test is because `ObjectEach` double-parses some values.  For example, when looking up key `person.name.fullName`, `ObjectEach` visits the `name` key within `person`, which causes the value `{\"fullName\": ..., ... }` to be scanned to find its extent. Then, inside the callback (which receives the byte slice for the value of `name`), we call `GetString` to extract the value of `fullName` within this inner object, which scans that object a second time.\r\n\r\nThe bottom line is that `ObjectEach` seems very efficient when scanning a leaf object (i.e., an object whose values are primitives), or when the inner objects will not be accessed (it should be efficient at simply skipping object values), but there is some overhead when values that are objects will be accessed further; in this case, `EachKey` or simple `Get`s may be a better choice."},"comment":{"url":"https://api.github.com/repos/buger/jsonparser/issues/comments/242732317","html_url":"https://github.com/buger/jsonparser/pull/58#issuecomment-242732317","issue_url":"https://api.github.com/repos/buger/jsonparser/issues/58","id":242732317,"user":{"login":"rami-dabain","id":1197104,"avatar_url":"https://avatars.githubusercontent.com/u/1197104?v=3","gravatar_id":"","url":"https://api.github.com/users/rami-dabain","html_url":"https://github.com/rami-dabain","followers_url":"https://api.github.com/users/rami-dabain/followers","following_url":"https://api.github.com/users/rami-dabain/following{/other_user}","gists_url":"https://api.github.com/users/rami-dabain/gists{/gist_id}","starred_url":"https://api.github.com/users/rami-dabain/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rami-dabain/subscriptions","organizations_url":"https://api.github.com/users/rami-dabain/orgs","repos_url":"https://api.github.com/users/rami-dabain/repos","events_url":"https://api.github.com/users/rami-dabain/events{/privacy}","received_events_url":"https://api.github.com/users/rami-dabain/received_events","type":"User","site_admin":false},"created_at":"2016-08-26T13:16:22Z","updated_at":"2016-08-26T13:16:22Z","body":"Is it possible to break out of the loop?\r\nDoing some logic of values with unspecified keys, if one of the values results in FALSE i don't need to continue iterating through the whole set... guess that would be a good case for both ObjectEach and ArrayEach"}}
{"actor":{"display_login":"rami-dabain"}}