Bill
Bill

Reputation: 2993

json keys replacement with overrides part

I have a configuration json file, here is a sample

{
  "version": "1.0",
  "producer": {
    "name": "app_name_{{ ENVIRONMENT }}_producer",
    "kms_key_alias": "alias/app_name_{{ ENVIRONMENT }}_producer_key",
    "shards": 1,
    "subscriptions": [
      {
        "name": "app_name1_{{ ENVIRONMENT }}_consumer",
        "account_id": "123456789012",
        "active": true
      },
      {
        "name": "app_name2_{{ ENVIRONMENT }}_consumer",
        "account_id": "987654321098",
        "active": true
      }
    ]
  },
  "consumers": [
    {
      "name": "app_name_{{ ENVIRONMENT }}_consumer",
      "kms_key_alias": "alias/app_name_{{ ENVIRONMENT }}_consumer_key",
      "shards": 1
    }
  ],
  "overrides": {
    "prod": {
      "producer": {
        "shards": 2,
        "subscriptions": [
          {
            "name": "app_name1_{{ ENVIRONMENT }}_consumer",
            "account_id": "123456789012",
            "active": false
          }
        ]
      },
      "consumers": [
        {
          "name": "app_name_{{ ENVIRONMENT }}_consumer",
          "shards": 3
        }
      ]
    }
  }
}

My target is to generate a final configuration for that environment. Environment is a variable.

The configuration for prod will be different. Such as producer.shards in prod will be 2, not 1.

The process is, read the json file, part of producer and consumers, save to a new variable new_json. This can be understood as default values.

{
  "producer": {
     ...
  }
  consumers": {
    ...
  }
} 

Then read the session of overrides, if the environment is prod, it will override the value in related keys.

I wrote the forEach codes to read each key in overrides, then I need confirm the key is list or map, then go the end of the part, replace the same key in new_json.

const json = JSON.parse(template)

if ({}.hasOwnProperty.call(overrides, environment)) {
  const env = overrides[environment];

  Object.keys(env).forEach((key){
      ...
  }
}

The sample json is a simple one. The real json has several hundred lines. So go through each key is not efficient method.

Are there any quick/smart ways to overrides any keys in overrides to new_json directly?

Update #1

With Object.assign(), I still need go though each key, otherwise, I got less keys.

For example, with below code, I got less in list of subscriptions.

$ cat a.js
const fs = require('fs');
const swig = require('swig-templates');

const environment='prod';

let template = swig.compileFile("jsoncontent.json");

template = template({
  ENVIRONMENT: environment,
});

const json = JSON.parse(template);

Object.assign(json.producer, json.overrides.prod.producer)
delete json.overrides

console.log(JSON.stringify(json, null, 2));

$ node a.js
{
  "version": "1.0",
  "producer": {
    "name": "app_name_prod_producer",
    "kms_key_alias": "alias/app_name_prod_producer_key",
    "shards": 2,
    "subscriptions": [
      {
        "name": "app_name1_prod_consumer",
        "account_id": "123456789012",
        "active": false
      }
    ]
  },
  "consumers": [
    {
      "name": "app_name_prod_consumer",
      "kms_key_alias": "alias/app_name_prod_consumer_key",
      "shards": 1
    }
  ]
}

Update #2

Thanks to point me to lodash.defaultsDeep, but when merge the maps in list, it has to be one to one matched in same position.

Use the exist as sample, if I adjust overrides a little bit, the subscriptions' first list, name is changed from app_name1 to app_name2

"overrides": {
    "prod": {
      "producer": {
        "shards": 2,
        "subscriptions": [
          {
            "name": "app_name2_{{ ENVIRONMENT }}_consumer",
            "account_id": "123456789012",
            "active": false
          }
        ]
      }
  }

The result will be:

{ shards: 2,
  subscriptions:
   [ { name: 'app_name2_prod_consumer',
       account_id: '123456789012',
       active: false },
     { name: 'app_name2_prod_consumer',
       account_id: '987654321098',
       active: true } ],
  name: 'app_name_prod_producer',
  kms_key_alias: 'alias/app_name_prod_producer_key' }

There are two app_name2 now.

Upvotes: 1

Views: 2509

Answers (1)

Avraham
Avraham

Reputation: 938

Object.assign seems to be exactly what you need.

Example:

var o1 = {
  a: 1,
  b: 2
}

var override = {
  a: 9
}

Object.assign(o1, override)
console.log(o1) // {a: 9, b: 2}

EDIT

Object.assign loops through only the root level.
For deep assignment you can use lodash.defaultsDeep:

var env = _.defaultsDeep(json.overrides.prod.producer, json.producer)

Upvotes: 3

Related Questions