首页 > 解决方案 > 如何使用 lodash 更新对象的嵌套数组

问题描述

我有一个嵌套的对象数组,如下面的结构。我想循环进入每个对象并检查特定字段是否与条件匹配。如果匹配,则更新该特定对象。

结构

{
  "condition": "and",
  "rules": [
    {
      "condition": "and",
      "rules": [
        {
          "field": "deviceName",
          "operator": "=",
          "value": "device01"
        },
        {
          "field": "temperature",
          "operator": ">",
          "value": 30
        },
        {
          "field": "mail",
          "operator": "to",
          "value": "edison@gmail.com"
        }
      ]
    },
    {
      "condition": "and",
      "rules": [
        {
          "field": "deviceName",
          "operator": "=",
          "value": "device02"
        },
        {
          "field": "voltage",
          "operator": "=",
          "value": 200
        },
        {
          "field": "log",
          "operator": "to",
          "value": "edison@gmail.com"
        },
        {
          "condition": "and",
          "rules": [
            {
              "field": "deviceName",
              "operator": "=",
              "value": "device04"
            },
            {
              "field": "voltage",
              "operator": "=",
              "value": 200
            },
            {
              "field": "mail",
              "operator": "to",
              "value": "edison@gmail.com"
            }
          ]
        }
      ]
    }
  ]
}

在上面的结构中,我正在检查每个规则 [] 并检查该字段是否具有值 email 或 log 。如果匹配,那么我将类型设置为操作 else 条件。

我已经尝试使用 map 来执行此操作,但它仅在第一级有效。假设如果对象有嵌套数组,我无法过滤它。

  const queryDetail = this.query.rules.map((query: any) => {
    const temp: any = {
      condition: {
        ...query
      }
    };
    if (query.field === 'mail' || query.field === 'log') {
      temp.type = 'action';
    } else {
      temp.type = 'condition';
    }
    return temp;
  });

  const updatedQuery = {
    condition: this.query.condition,
    rules: queryDetail
  };

标签: javascriptarrayslodash

解决方案


为此,您不需要 Lodash。您可以采用递归方法。

首先,规则分为“简单”和“复杂”

  • 简单的规则有fieldoperatorvalue字段。
  • 复杂的规则有一个rules属性。

考虑到这一点,将以下逻辑应用于每个规则:

  1. 转换规则克隆它。
  2. 如果这是一个复杂的规则,那么:
    • 检查它的子规则。如果任何直接子级具有值为'email'or的字段'log',则将type当前复杂规则的 设置为'action'。否则将其设置为'condition'. 即使子规则很复杂,这也会起作用,因为它们没有field属性,因此将被视为与过滤器不匹配的简单规则一样。
    • 对所有子规则应用相同的逻辑。

const data = { "condition": "and", "rules": [{ "condition": "and", "rules": [{ "field": "deviceName", "operator": "=", "value": "device01" }, { "field": "temperature", "operator": ">", "value": 30 }, { "field": "mail", "operator": "to", "value": "edison@gmail.com" } ] }, { "condition": "and", "rules": [{ "field": "deviceName", "operator": "=", "value": "device02" }, { "field": "voltage", "operator": "=", "value": 200 }, { "field": "log", "operator": "to", "value": "edison@gmail.com" }, { "condition": "and", "rules": [{ "field": "deviceName", "operator": "=", "value": "device04" }, { "field": "voltage", "operator": "=", "value": 200 }, { "field": "mail", "operator": "to", "value": "edison@gmail.com" } ] } ] } ] }


function convertRule(obj) {
  //clone the rule
  const result = {...obj};
  const isComplexRule = "rules" in obj;

  if (isComplexRule) {
    //check sub-rules
    const isActionRule = obj.rules.some(checkSimpleRule);
    
    //set the appropriate action
    if (isActionRule) {
      result.type = 'action';
    } else {
      result.type = 'condition';
    }
    
    //re-run the same logic on each sub-rule recursively
    result.rules = result.rules.map(convertRule)
  }

  //return the cloned object
  return result;
}

function checkSimpleRule(rule) {
  return rule.field === 'mail' || rule.field === 'log'
}
const queryDetail = convertRule(data)

console.log(queryDetail)


推荐阅读