Nidhin Kumar
Nidhin Kumar

Reputation: 3579

How to update the nested array of object using lodash

I am having an nested array of objects like the below structure. I would like to loop into each object and check whether the particular field matches with a condition or not.If it matches then update that particular object.

Structure

{
  "condition": "and",
  "rules": [
    {
      "condition": "and",
      "rules": [
        {
          "field": "deviceName",
          "operator": "=",
          "value": "device01"
        },
        {
          "field": "temperature",
          "operator": ">",
          "value": 30
        },
        {
          "field": "mail",
          "operator": "to",
          "value": "[email protected]"
        }
      ]
    },
    {
      "condition": "and",
      "rules": [
        {
          "field": "deviceName",
          "operator": "=",
          "value": "device02"
        },
        {
          "field": "voltage",
          "operator": "=",
          "value": 200
        },
        {
          "field": "log",
          "operator": "to",
          "value": "[email protected]"
        },
        {
          "condition": "and",
          "rules": [
            {
              "field": "deviceName",
              "operator": "=",
              "value": "device04"
            },
            {
              "field": "voltage",
              "operator": "=",
              "value": 200
            },
            {
              "field": "mail",
              "operator": "to",
              "value": "[email protected]"
            }
          ]
        }
      ]
    }
  ]
}

In the above structure i am checking each rules[] and check whether the field has the value email or log .If it matches then i am setting the type as action else condition.

I have tried map to do it but it works only at the first level. suppose if the object has nested array i couldn't able to filter it.

  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
  };

Upvotes: 1

Views: 1398

Answers (1)

VLAZ
VLAZ

Reputation: 28969

You do not need Lodash for this. You can take a recursive approach.

First off, rules are divided to "simple" and "complex"

  • simple rules have field, operator, and value fields.
  • complex rules have a rules property.

With this in mind, apply the following logic to each rule:

  1. Convert the rule cloning it.
  2. If it's a complex rule, then:
    • check its sub rules. If any immediate children have a field with value 'email' or 'log', then set the type of the current complex rule to 'action'. Otherwise set it to 'condition'. This will work even if the sub-rules are complex, since they do not have the field property and thus will be treated the same as if they were simple rules that didn't match the filter.
    • apply the same logic to all sub-rules.

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


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)

Upvotes: 1

Related Questions