1

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
  };
2
  • Your data is invalid, it's complaining about a missing ] Commented Mar 24, 2020 at 6:41
  • @VLAZ i have updated the data Commented Mar 24, 2020 at 6:43

1 Answer 1

1

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)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.