4

i want to delete the only low-level object(for example in below code, under personal data there are two objects... i want to delete one object where action: old) under each section, where "action": "OLD"

I'm using lodash in my project

[
  {
    "clientDetails": {
      "personalData": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    },
    "clientAddress": {
      "primaryAddress": [
        {
          "action": "OLD",
          "id": "12345"
        },
        {
          "action": "NEW",
          "id": "12445"
        }
      ],
      "secondaryAddress": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    }
  },
  {
    "clientDemise": {
      "deathDetails": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    },
    "clientMarital": {
      "divorceInformation": [
        {
          "action": "OLD",
          "id": "12345"
        },
        {
          "action": "NEW",
          "id": "12445"
        }
      ],
      "marraigeInformation": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    }
  }
]

sorry for the wrong presentation, this is the first time I'm posting a question

1
  • What should be the o/p for this? Commented Oct 25, 2018 at 6:15

7 Answers 7

2

Just few lines can achieve this considering

input = your input

This peace of code will do the work

for (var i of input) {
  for (var j in i) {
   var ob = i[j];
   for (var k in ob) {
     var index = _.findIndex(ob[k], {'action': 'OLD'});
     if (index > -1) {
       ob[k].splice(index, 1);
     }
   }
 }
}
Sign up to request clarification or add additional context in comments.

7 Comments

This is a nice, short solution. You can remove the toRemove variable, btw. Also, you could turn this into a code snippet, and just include lodash as an external library.
Thank u so much for the suggestion, I removed the unnecessary variable, Will create code snippet if needed.
But this can't be used to remove multiple entry of unwanted data (in case required)
your code works ... thanks.. but it throws error ob[k].splice is not a function for example in above code if there is no primary address @ShyamTayal
I am considering last level fields to be an array, If not so add a type check in the third loop to avoid any error. Hope it helps
|
1

You can achieve this via something like this without lodash:

var data = [{ "clientDetails": { "personalData": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientAddress": { "primaryAddress": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "secondaryAddress": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } }, { "clientDemise": { "deathDetails": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientMarital": { "divorceInformation": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "marraigeInformation": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } } ]

const removeOld = (data) => data.map(x => 
   Object.entries(x).reduce((r, [k,v]) => {
      r[k] = Object.entries(v).map(([o,p]) => 
        ({[o]: p.filter(n => n.action != 'OLD')}))
      return r
   },{}))

console.log(removeOld(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Using map, Object.entries, reduce and filter.

Another way would be to utilize recursion similar to @Vanojx1 approach but in ES6:

var data = [{ "clientDetails": { "personalData": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientAddress": { "primaryAddress": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "secondaryAddress": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } }, { "clientDemise": { "deathDetails": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientMarital": { "divorceInformation": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "marraigeInformation": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } } ]

const removeOld = (data) => 
  Array.isArray(data) ? data.filter(x => x.action != 'OLD').map(x => removeOld(x)) :
  typeof(data) == 'object' ? Object.entries(data).reduce((r, [k,v]) => (r[k] = removeOld(v), r), {}) : 
  data

console.log(removeOld(data))

Comments

1

You can use JavaScript filters. Reduce your bundle size by not using lodash.

// it's upto you, you can use new Array() as well and insert if(ktm.action==='NEW')
clients = clients.filter(function(itm) {
  Object.keys(itm).forEach(function(Okey, Ovalue) {
    Object.keys(itm[Okey]).forEach(function(inkey, invalue) {
      itm[Okey][inkey].filter(function(ktm) {
        if (ktm.action === 'OLD') {
          // perform your logic, either you can insert into new Array() or 
          // delete that object and return clients
        }
      });
    });
  });
});

Comments

1

Let's not mutate the original input data, clone it with a customizer, and reject the unwanted stuffs (if they exists) inside the customizer to have cleaner cloned output as expected. You can use lodash#cloneDeepWith

_.cloneDeepWith(input, v => _.find(v, {action: "OLD"}) ? _.reject(v, {action: "OLD"}) : undefined);

This is just an example of having (hard coded) of what you want to reject. but you can wrap this in a callback and take the reject criteria as an argument to make it dynamic.

So here we go:

let input = [{"clientDetails":{"personalData":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]},"clientAddress":{"primaryAddress":[{"action":"OLD","id":"12345"},{"action":"NEW","id":"12445"}],"secondaryAddress":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]}},{"clientDemise":{"deathDetails":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]},"clientMarital":{"divorceInformation":[{"action":"OLD","id":"12345"},{"action":"NEW","id":"12445"}],"marraigeInformation":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]}}],
    clear = (input, rej) => (
      _.cloneDeepWith(input, v => _.find(v, rej) ? _.reject(v, rej) : undefined)
    ),
    res;
  
res = clear(input, {action: "OLD"}); //you can filter out action: OLD
console.log(res);

res = clear(input, {action: "NEW"}); //you can filter out action: NEW
console.log(res);

res = clear(input, d => d.action==="OLD"); //you can filter with custom callback with complex logic
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

1 Comment

tks amazing lodash - you saved my bacon
0

If the structure of your data is going to be fairly consistent (i.e. similar to what you've included in your question), you could do something like this:

const mapObj = (f, obj) => {
    return Object.keys(obj).reduce((acc, key) => {
        acc[key] = f(obj[key], key)
        return acc
    }, {})
}

const filterData = data => {
    // the data itself is an array, so iterate over each item in the array
    return data.map(x1 => {
        // x1 is an object, so need to iterate over each item in the object
        return mapObj(x2 => {
            // x2 is an object, so need to iterate over each item in the object
            return mapObj(x3 => {
                // x3 is an array of objects. each item in the array has an action key which could equal "NEW" or "OLD". get rido of the items with action === "OLD"
                return x3.filter(x4 => x4.action !== "OLD")
            }, x2)
        }, x1)
    })
}

const data = [
  {
    "clientDetails": {
      "personalData": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    },
    "clientAddress": {
      "primaryAddress": [
        {
          "action": "OLD",
          "id": "12345"
        },
        {
          "action": "NEW",
          "id": "12445"
        }
      ],
      "secondaryAddress": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    }
  },
  {
    "clientDemise": {
      "deathDetails": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    },
    "clientMarital": {
      "divorceInformation": [
        {
          "action": "OLD",
          "id": "12345"
        },
        {
          "action": "NEW",
          "id": "12445"
        }
      ],
      "marraigeInformation": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    }
  }
]

const result = filterData(data)
console.log(result)

If you want a more generic solution that can take data of any structure and just removes all objects with an action equal to 'OLD':

const reduceObj = (f, initial, obj) => {
    return Object.keys(obj).reduce((acc, key) => {
        return f(acc, obj[key], key)
    }, initial)
}

const isObject = x => x !== null && typeof x === 'object'

const removeAllOld = data => {
    if(Array.isArray(data)) {
        return data.reduce((acc, value) => {
            // don't include the item if it has a key named 'action' that is equal to 'OLD'
            if(value.action && value.action === 'OLD') return acc

            acc.push(removeAllOld(value))
            return acc
        }, [])
    }
    else if(isObject(data)) {
        return reduceObj((acc, value, key) => {
            // don't include the item if it has a key named 'action' that is equal to 'OLD'
            if(value.action && value.action === 'OLD') return acc

            acc[key] = removeAllOld(value)
            return acc
        }, {}, data)
    }
    else {
        return data
    }
}

const data = [
  {
    "clientDetails": {
      "personalData": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    },
    "clientAddress": {
      "primaryAddress": [
        {
          "action": "OLD",
          "id": "12345"
        },
        {
          "action": "NEW",
          "id": "12445"
        }
      ],
      "secondaryAddress": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    }
  },
  {
    "clientDemise": {
      "deathDetails": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    },
    "clientMarital": {
      "divorceInformation": [
        {
          "action": "OLD",
          "id": "12345"
        },
        {
          "action": "NEW",
          "id": "12445"
        }
      ],
      "marraigeInformation": [
        {
          "action": "NEW",
          "id": "12345"
        },
        {
          "action": "OLD",
          "id": "12445"
        }
      ]
    }
  }
]

console.log(removeAllOld(data))

Comments

0

Structure independent solution checking for action in each object node

var data=[{clientDetails:{personalData:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]},clientAddress:{primaryAddress:[{action:"OLD",id:"12345"},{action:"NEW",id:"12445"}],secondaryAddress:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]}},{clientDemise:{deathDetails:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]},clientMarital:{divorceInformation:[{action:"OLD",id:"12345"},{action:"NEW",id:"12445"}],marraigeInformation:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]}}];

const reducer = (curr) => {
  if(_.isArray(curr))
    return _(curr)
      .filter(el => !('action' in el && el.action == 'OLD'))
      .map(el => reducer(el))
      .value()
  else if(_.isObject(curr)) {
    return _(curr)
      .mapValues(el => reducer(el))
      .value()
  } else
    return curr;
};

console.log(reducer(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Comments

0

you can do a deep copy like this:

    const array = [
      {
        "clientDetails": {
          "personalData": [
            {
              "action": "NEW",
              "id": "12345"
            },
            {
              "action": "OLD",
              "id": "12445"
            }
          ]
        },
        "clientAddress": {
          "primaryAddress": [
            {
              "action": "OLD",
              "id": "12345"
            },
            {
              "action": "NEW",
              "id": "12445"
            }
          ],
          "secondaryAddress": [
            {
              "action": "NEW",
              "id": "12345"
            },
            {
              "action": "OLD",
              "id": "12445"
            }
          ]
        }
      },
      {
        "clientDemise": {
          "deathDetails": [
            {
              "action": "NEW",
              "id": "12345"
            },
            {
              "action": "OLD",
              "id": "12445"
            }
          ]
        },
        "clientMarital": {
          "divorceInformation": [
            {
              "action": "OLD",
              "id": "12345"
            },
            {
              "action": "NEW",
              "id": "12445"
            }
          ],
          "marraigeInformation": [
            {
              "action": "NEW",
              "id": "12345"
            },
            {
              "action": "OLD",
              "id": "12445"
            }
          ]
        }
      }
    ]    
    function removeOldAction(a) {
    if (a instanceof Array) {
        let copiee = [];
        for (let item in a) {
            const propValue = removeOldAction(a[item]);
            if(propValue) {
                copiee.push(propValue);
            }
        }
        return copiee;
    }
    if (a instanceof Object) {
        if (a['action'] === 'OLD') { 
            return; 
        }
        let copiee = {};
        for (let key in a) {
            copiee[key] = removeOldAction(a[key]);
        }
        return copiee;
    } 
    return a;
}

    console.log(removeOldAction(array));

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.