22

What JSON format is a better choice for key value pairs and why?

[{"key1": "value1"}, {"key2": "value2"}]

Or:

[{"Name": "key1", "Value": "value1"}, {"Name": "key2", "Value": "value2"}]

Or:

{"key1": "value1", "key2": "value2"}

The first variant seems more compact and more "semantically meaningful". The second variant seems more evenly structured which might help processing it. The 3rd variant seems even more semantic.

The key value pairs will be used to attach arbitrary data to some other item. The data must be serialized as JSON to round-tip it through a system.

  • 3
    Unless you require ordering, why not consider {"key1": "value1", "key2": "value2"}? – kennytm Jun 7 '16 at 16:40
  • 4
    JSON is already a (nestable) dictionary. – Kasey Speakman Jun 7 '16 at 16:41
  • 1
    Your problem is description is broad enough to say that any of those formats will work, and the real question is how to make it simpler to consume, which depends on what technologies clients use. – scriptin Jun 7 '16 at 17:36
  • You should use the simplest that meets your needs, hopefully that will be the simple object form (#3). However, if you're looking for even more options, you can use two arrays in parallel, one for keys, and one for values; that will be pretty much as compact as possible while still supporting object keys & duplicate keys (which would not be supported with #3). – Erik Eidt Jun 7 '16 at 18:50
9

Whether you choose the first or the third option depends on your use case. If you are modeling many different instances of the same type of thing, choose the first. For example, you have a list of people. If you are modeling many different attributes of one thing, choose the third. You can have repeated keys in the first format, but not in the third.

The second option is terrible, and I've yet to find an appropriate use case for it. The reason it's terrible, in addition to being more verbose, is that for single-level JSON, it breaks most libraries' automatic conversion to a dictionary/map. For deeply-nested JSON, it breaks the XPath-like query interface.

This makes it a pain to work with. And if you don't know your keys at compile time, you will want a dictionary or XPath interface, because you won't be able to convert it to a class. It may not seem like a big deal now, but the longer you have a data format, the harder it will be to change.

  • 5
    The big advantage of the second option is that it works with non-string keys, in particular composite keys. – CodesInChaos Jun 7 '16 at 18:15
  • 1
    The second option is terrible and you have yet to find a use case? Array of dictionaries with many key/value pairs must be about the most common format for transmitting multiple objects. – gnasher729 Jun 7 '16 at 21:18
  • 2
    @gnasher729, in your "most common format" case the real keys are all on the left-hand side: [{"key1": "value1", "key2": "value2"}]. The second format here is putting the real key on the right-hand side, and using another key called "Name" to point you to the real key, making it extremely difficult to parse with standard tools. – Karl Bielefeldt Jun 7 '16 at 22:14
  • I'll give you that one, @CodesInChaos. Even there, though, it would have to be a very special case. I've never seen the need for it in the wild. – Karl Bielefeldt Jun 7 '16 at 22:17
  • 3
    Sorry, but this is a bad answer. The 2nd option is both very commonly used and advised. It allows for keys flexibility, it allows extension (with more value/metadata fields) without breaking consumers, and it can preserve the element order. Plus, the reasons given are bogus: it doesn't break any "automatic conversion" (it merely respects the author's presentation as array) and it works fine with a XPath-like query interface. The only downside is the increased verbosity. – Hejazzman Mar 19 '18 at 11:36
5

The 3rd format is in general the best. However, here's an example of something suitable for the 1st format:

[{
  "username": "foo",
  "id": 1
}, {
  "username": "bar",
  "id": 2
}, {
  "username": "baz",
  "id": 3
}]

Here each object refers to a separate thing (and each object uses the same keys as the others, so they couldn't be merged). However, each object in the list is stored as { "username": "foo", "id": 1 } rather than [{ "username": "foo" }, { "id": 1 }] because 1) it's shorter and 2) it's referring to one thing with a username and an id, not one thing with a username and another thing with an id.

The problem with the second option is that it becomes very verbose both as JSON and to work with. However, it could be used if you need to store meta-information about the property. An example:

{
  "key": "foo",
  "value": 1,
  "mutable": true
}

Here mutable refers to a hypothetical case of whether you can modify the property itself, not the parent object. Meta-information like this is similar to JavaScript's Object.defineProperty, which stores "configurable", "enumerable", and "writable" information about a property.

  • I was trying to use the first format for some JSON i was sending to a C# REST end point and it was not converting to a dictionary object. Converting it to the 3rd format cleared that up. – fizch Mar 29 '18 at 3:09
5

You say these are key / value pairs. In that case, use #3: dictionary of key / value pairs.

If these are not key / value pairs, then don't call them "keys" and "values" and use #2, an array of dictionaries with arbitrary contents.

Structure #1 is just daft unless you need key / value pairs but also their order. Which you rarely do.

3

Put your self in the shoes of the person receiving the json. If i don't know the key name how am i supposed to retrieve it with the first or the last format? You can loop through the json of course but since all three formats achieve the same result it's just a question of syntax. I think this is the only meaningful question: if you know the key names the first or last option are more compact, if not the second choice is more understandable.

protected by gnat Nov 1 '17 at 11:57

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.