Reputation: 2993
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?
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
}
]
}
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
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