Skip to content

Instantly share code, notes, and snippets.

@LarsFronius
Last active January 11, 2019 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LarsFronius/d281f33da6f2756e197e921b0c641909 to your computer and use it in GitHub Desktop.
Save LarsFronius/d281f33da6f2756e197e921b0c641909 to your computer and use it in GitHub Desktop.
Representing Hash/Dicts/Hashmaps as Key-Value

Representing Hash/Dicts/Hashmaps/Objects as Key-Value

Docker is on a rise, Terraform only allows flat maps or lists and generally the "Twelve-Factor App" manifest suggests storing configuration in environment variables, which are technically key-value pairs.

However, if you find yourself on a path of migrating your app towards twelve-factor, and for some reasons uses nested dictionaries/hashes as a configuration format, it can come in handy to have a standard library to interact with the two different representation formats of a key-value ENV variable list and the nested dict/hash representation.

This gist is meant to collect the different libraries or code snippets in different programming languages to interact with the two representation formats.

Python

https://github.com/gmr/flatdict For example:

foo = {'foo': {'bar': 'baz', 'qux': 'corge'}}

can represented as following, with a colon delimiter:

{'foo:bar': 'baz',
 'foo:qux': 'corge'}

Ruby

Looking for library, to get a nested hash into a flat key-value "dotted" notation, this should do:

class Hash
  def self.to_dotted_hash(hash, recursive_key = "")
    hash.each_with_object({}) do |(k, v), ret|
      key = recursive_key + k.to_s
      if v.is_a? Hash
        ret.merge! to_dotted_hash(v, key + ".")
      else
        ret[key] = v
      end
    end
  end
end

Javascript

var flatten = require('flat')

flatten({
    key1: {
        keyA: 'valueI'
    },
    key2: {
        keyB: 'valueII'
    },
    key3: { a: { b: { c: 2 } } }
})

// {
//   'key1.keyA': 'valueI',
//   'key2.keyB': 'valueII',
//   'key3.a.b.c': 2
// }
const jsonjs = require('jsonjs');
var foo = {foo: {bar: 'baz', qux: 'corge'}};
var flat = jsonjs.utils.flatten(foo, ':');
// => { 'foo:bar': 'baz', 'foo:qux': 'corge' }
jsonjs.utils.unflatten(flat, ':').object();
// => { foo: { bar: 'baz', qux: 'corge' } }

var baa = { bar: { arr: ['a', 'b'], hosts: [ { port: 3000, host: 'localhost' }, { port: 3001, host: 'localhost' } ] } };
jsonjs.utils.flatten(baa, ':')
// => 
//  { 'bar:arr:0': 'a',
//    'bar:arr:1': 'b',
//    'bar:hosts:0:port': 3000,
//    'bar:hosts:0:host': 'localhost',
//    'bar:hosts:1:port': 3001,
//    'bar:hosts:1:host': 'localhost' }

Golang

nested := `{
  "one": {
    "two": [
      "2a",
      "2b"
    ]
  },
  "side": "value"
}`

flat, err := flatten.FlattenString(nested, "", flatten.DotStyle)

// output: `{ "one.two.0": "2a", "one.two.1": "2b", "side": "value" }`

Or Go maps directly.

nested := map[string]interface{}{
   "a": "b",
   "c": map[string]interface{}{
       "d": "e",
       "f": "g",
   },
   "z": 1.4567,
}

flat, err := flatten.Flatten(nested, "", flatten.RailsStyle)

// output:
// map[string]interface{}{
//  "a":    "b",
//  "c[d]": "e",
//  "c[f]": "g",
//  "z":    1.4567,
// }

See godoc for API.

@joona
Copy link

joona commented Sep 8, 2016

https://github.com/Inbot/jsonjs

const jsonjs = require('jsonjs');
var foo = {foo: {bar: 'baz', qux: 'corge'}};
var flat = jsonjs.utils.flatten(foo, ':');
// => { 'foo:bar': 'baz', 'foo:qux': 'corge' }
jsonjs.utils.unflatten(flat, ':').object();
// => { foo: { bar: 'baz', qux: 'corge' } }

var baa = { bar: { arr: ['a', 'b'], hosts: [ { port: 3000, host: 'localhost' }, { port: 3001, host: 'localhost' } ] } };
jsonjs.utils.flatten(baa, ':')
// => 
//  { 'bar:arr:0': 'a',
//    'bar:arr:1': 'b',
//    'bar:hosts:0:port': 3000,
//    'bar:hosts:0:host': 'localhost',
//    'bar:hosts:1:port': 3001,
//    'bar:hosts:1:host': 'localhost' }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment