M
M
Maksipes2021-09-21 21:51:33
JavaScript
Maksipes, 2021-09-21 21:51:33

How to change a value in an object along its path?

There is an array of objects in which there is a large nesting, including through arrays. For example:

export const data = [
  {
    created_at: "30.08.2021",
    entry: {
      created_at: "30.08.2021",
    },
    arr: [
      {
        id: 111,
        created_at: "30.08.2021",
        updated_at: "30.08.2021",
        subEntry: {
          id: 222,
          created_at: "30.08.2021",
          updated_at: null,
          date_assigned_on: "09.09.2021",
          date_prepared_for: "10.09.2021",
        }
      }
    ]
  }
];

We need to modify this array by converting all strings with dates in it, no matter how deeply nested, into objects.

Since you cannot rely on the name of the keys, there is an idea to use PATHs, like this:

[
  'created_at',
  'entry.created_at',
  'arr.0.created_at',
  'arr.0.subEntry.updated_at',
]

That is, we list all the values ​​that need to be converted. In this case, "0" means - in the array.

Interested in ready-made solutions - libraries or links.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
0
0xD34F, 2021-09-21
@maksipes

function setNestedVal(root, path, val) {
  const keys = path.split('.');
  const key = keys.pop();
  keys.reduce((acc, n) => acc[n] ??= {}, root)[key] = val;
}


setNestedVal(data, '0.arr.0.str', 'hello, world!!');
setNestedVal(data, '0.arr.1.num', 666);

Interested in turnkey solutions?

https://lodash.com/docs/4.17.15#set
In general, considering what kind of problem you are trying to solve...
We need to modify this array by converting all strings with dates in it, no matter how deeply nested, into objects.

...you don't need any of the above. We make a function that recursively traverses the passed object, checking what the values ​​are - if a string with a date, then performs the specified conversion:
const replaceValues = (data, test, transform) =>
  test(data)
    ? transform(data)
    : data instanceof Array
      ? data.map(n => replaceValues(n, test, transform))
      : data instanceof Object
        ? Object.fromEntries(Object
            .entries(data)
            .map(([ k, v ]) => [ k, replaceValues(v, test, transform) ])
          )
        : data;


const newData = replaceValues(
  data,
  x => typeof x === 'string' && /^\d{2}\.\d{2}\.\d{4}$/.test(x),
  str => new Date(str.split('.').reverse().join('-'))
);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question