node.js - 用覆盖部分替换 json 键
问题描述
我有一个配置 json 文件,这是一个示例
{
"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
}
]
}
}
}
我的目标是为该环境生成最终配置。环境是一个变量。
的配置prod
会有所不同。例如producer.shards
在 prod 中将是 2,而不是 1。
过程是,读取 json 文件,其中的一部分producer
,consumers
保存到一个新的变量new_json
中。这可以理解为默认值。
{
"producer": {
...
}
consumers": {
...
}
}
然后读取覆盖的会话,如果环境是prod
,它将覆盖相关键中的值。
我编写了forEach
读取每个键的代码overrides
,然后我需要确认键是列表或映射,然后转到该部分的末尾,替换 中的相同键new_json
。
const json = JSON.parse(template)
if ({}.hasOwnProperty.call(overrides, environment)) {
const env = overrides[environment];
Object.keys(env).forEach((key){
...
}
}
示例 json 是一个简单的示例。真正的 json 有几百行。所以遍历每个键不是有效的方法。
是否有任何快速/智能的方法可以直接覆盖覆盖中的任何键new_json
?
更新#1
使用Object.assign(),我仍然需要遍历每个键,否则,我得到的键更少。
例如,使用下面的代码,我在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
}
]
}
更新#2
感谢我指向lodash.defaultsDeep,但是当合并列表中的地图时,它必须在同一位置一对一匹配。
使用存在作为示例,如果我稍微调整overrides
一下,订阅的第一个列表,名称从更改app_name1
为app_name2
"overrides": {
"prod": {
"producer": {
"shards": 2,
"subscriptions": [
{
"name": "app_name2_{{ ENVIRONMENT }}_consumer",
"account_id": "123456789012",
"active": false
}
]
}
}
结果将是:
{ 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' }
现在有两个app_name2
。
解决方案
Object.assign似乎正是您所需要的。
例子:
var o1 = {
a: 1,
b: 2
}
var override = {
a: 9
}
Object.assign(o1, override)
console.log(o1) // {a: 9, b: 2}
编辑
Object.assign 仅循环通过根级别。
对于深度分配,您可以使用lodash.defaultsDeep:
var env = _.defaultsDeep(json.overrides.prod.producer, json.producer)
推荐阅读
- javascript - 使用 Sheet.js 包导出时,如何将 CSV 中的所有单元格格式化为文本?
- c# - C#弹跳立方体游戏,从中心100px移除立方体
- firebase - React Native Pdf 未显示
- php - 如何在 foreach 循环中调用不同的多语言国家列表?
- linux - 无法在 Rocky 8.4 上从源代码构建 DSC (v1.2.1-0)/OMI (1.6.8-1)
- reactjs - 我应该在 redux 工具包中的哪里设置 localStorage
- c - 具有近乎无限增长的匿名 mmap
- vue.js - 将父 vm 作为道具传递给组件
- ubuntu - 找不到命令'nft add set inet filter f2b-recidive
- javascript - ajax 成功后刷新/重新加载页面但防止页面闪烁