首页 > 解决方案 > 在嵌套的 json 对象中按键获取值并替换为第二个 json 值

问题描述

我有一个 json 对象(firstObj)它可以嵌套,我有一个包含键/值对的第二个对象。我想通过匹配值将第二个对象的值替换为第一个对象的值并执行它的操作。

let firstObj = {
    amount_money: {
       amount: {
           mapped_field: 'payment_amt',
           operation: '/10'
       },
       currency: {
          mapped_field: 'payment_cur',
          operation: null
       }
    },
   source_id: {
          mapped_field: 'request_id',
          operation: null
   },
  ship: [ 
            { mapped_field: 'ship_country[0]', operation: null },
            { mapped_field: 'ship_country[1]', operation: null } 
        ]
 };
       

我的第二个对象

let secondObj = {
     payment_amt: 100,
     payment_cur: 'USD',
     request_id: '123ASD',
     ship_country: [ 
                     { code: 'USA', Title: 'America' }, 
                     { code: 'UK', Title: 'England' } 
                   ] 
    };

我想要这样的东西

{
  amount_money: {
     amount: 10
     currency: 'USD'
  },
  source_id: '123ASD',
  ship: [ {America: 'USA'}, {England: 'UK'}]
}

非常感谢您的热心帮助,谢谢!

标签: javascriptnode.jsjsonnested-object

解决方案


解决更新的问题

// const objectScan = require('object-scan');

const myTemplate = { amount_money: { amount: { mapped_field: 'payment_amt', operation: '/10' }, currency: { mapped_field: 'payment_cur', operation: null } }, source_id: { mapped_field: 'request_id', operation: null }, ship: [{ mapped_field: 'ship_country[0]', operation: null }, { mapped_field: 'ship_country[1]', operation: null }] };
const myVariables = { payment_amt: 100, payment_cur: 'USD', request_id: '123ASD', ship_country: [{ code: 'USA', Title: 'America' }, { code: 'UK', Title: 'England' }] };

const apply = (input, operation) => {
  if (operation === null) {
    return input;
  }
  const action = /(?<op>[/+])(?<v>\d+)/g.exec(operation);
  if (action === null) {
    throw new Error(`Unknown operation: ${operation}`);
  }
  if (action.groups.op === '/') {
    return input / action.groups.v;
  }
  // action.groups.op === '+'
  return input + action.groups.v;
};

const compile = objectScan(['**.mapped_field'], {
  rtn: 'count',
  filterFn: ({ gparent, gproperty, parent, value, context }) => {
    const data = objectScan([value], { rtn: 'value', abort: true })(context);
    if (data === undefined) {
      return false;
    }
    gparent[gproperty] = apply(data, parent.operation);
    return true;
  }
});

console.log(compile(myTemplate, myVariables));
// => 5

console.log(myTemplate);
// => { amount_money: { amount: 10, currency: 'USD' }, source_id: '123ASD', ship: [ { code: 'USA', Title: 'America' }, { code: 'UK', Title: 'England' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@16.0.2"></script>

免责声明:我是对象扫描的作者


旧答案(问题的预编辑)

这是使用object-scan的通用解决方案。

// const objectScan = require('object-scan');

const template = { amount_money: { amount: { mapped_field: 'payment_amt', operation: '/10' }, currency: { mapped_field: 'payment_cur', operation: null } }, source_id: { mapped_field: 'request_id', operation: null } }
const values = { payment_amt: 100, payment_cur: 'USD', request_id: '123ASD' };

const apply = (input, operation) => {
  if (operation === null) {
    return input;
  }
  const action = /(?<op>[/+])(?<v>\d+)/g.exec(operation);
  if (action === null) {
    throw new Error(`Unknown operation: ${operation}`);
  }
  if (action.groups.op === '/') {
    return input / action.groups.v;
  }
  // action.groups.op === '+'
  return input + action.groups.v;
};

const compile = objectScan(['**.*.mapped_field'], {
  rtn: 'count',
  filterFn: ({ gparent, gproperty, parent, value, context }) => {
    if (value in context) {
      gparent[gproperty] = apply(context[value], parent.operation);
      return true;
    }
    return false;
  }
});

console.log(compile(template, values));
// => 3

console.log(template);
// => { amount_money: { amount: 10, currency: 'USD' }, source_id: '123ASD' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@16.0.2"></script>

免责声明:我是对象扫描的作者

重要的:

  • 请注意,这确实会修改模板对象。如果不需要,您可以克隆它。
  • 您可以使用 eval,但它被认为是危险的。这需要做更多的工作,但您可能应该自己实现所有支持的操作,就像我在“应用”函数中开始的那样。
  • 您也许可以使用例如safe-eval,但我没有使用它的经验,也不知道它有多安全。如果您担心任何形式的注入攻击,请不要使用它。

编辑(根据评论中的要求)

这是如何工作的:

  • apply是一个辅助函数,接受输入和操作。我们使用正则表达式来确定运算符,然后将其应用于输入
  • compile是核心逻辑。我们以 为目标字段**.*.mapped_field,其中 single*确保我们以对象而不是数组为目标
  • filterFn我们检查值是否已知context(即values)。如果是这种情况,则使用祖父母 ( gparent) 和祖属性 ( gproperty) 更新值。的所有参数filterFn都是相对于目标的(在这种情况下mapped_field
  • count只是返回值(在这种情况下,多久true返回一次filterFn

这在对象扫描中都有详细记录。看看那里。放入日志语句也可能对您的理解有很大帮助!


推荐阅读