-2

What I need to do is modify a TypeScript object by doing a key search (the key can be repeated, so I need to check that it belongs to the right branch) and modifying the corresponding object. In short if this is the object:

{
   requirements: {
     general_info: {
       aircraft: {
         payload: { '@_unit': 'kg' },
         autopilot_ratio: '',
       },
       power: {
         number_of_engines: '',
       },
       geometrical: {
         payload: { '@_unit': 'kg' },
         design_approach: { target: '' },
       },
     },
   },
}

must be transformed into:

{
   requirements: {
     general_info: {
       aircraft: {
         payload: { '@_unit': 'hg', '#text': 3000},
         autopilot_ratio: '',
       },
       power: {
         number_of_engines: '',
       },
       geometrical: {
         payload: { '@_unit': 'kg' },
         design_approach: { target: '' },
       },
     },
   },
}

I understand that it has to be a recursive function. I tried to write the following function but I don't know how to prevent nested objects from being inserted multiple times

const updateObject = (json: any, searchKey: string, unit: string, value: number): Object => {
  return Object.keys(json).map((key: string) => {
    if (key !== searchKey && typeof json[key] !== 'string') {
      return updateObject(json[key], searchKey, unit, value);
    } else {
      if (typeof json[key] !== 'string') {
        json[key]['@_unit'] = unit;
        json[key]['#text'] = value;
        return json;
      } else {
        return json;
      }
    }
  });
};

console.dir(updateObject(json, 'payload', 'hg', 3000), { depth: null });

Among other things, this changes all the payload instances, it would also be useful to pass requirements.general_info.aircraft.payload as searchKey so as to change only the desired one

EDIT The object { '@_unit': 'kg' } has a fixed format and I can already know a priori that it will be { '@_unit': 'hg', '#text': 3000} the problem is but replace it in the right place of the JSON because it is not unique, otherwise a JSON.parse(JSON.stringify(json).replace() would have been enough.

10
  • "I understand that it has to be a recursive function..." Does it? In your example, payload only appears at a single level in the object tree (as a child of a child of a child of requirements). You don't need a recursive function if that's the case. Commented Oct 20, 2023 at 9:23
  • You're probably right, it's the only way I've found to cycle through nested objects Commented Oct 20, 2023 at 9:29
  • If you already have the path to the object to update (ie requirements.general_info.aircraft.payload) you could use something like JSONPath to get the correct object. If you don't have the full path, you do you determine, whether to update or not a certain payload object (ie you want to update the payload of the aircraft object but not of the geometrical Commented Oct 20, 2023 at 9:40
  • Does this answer your question? JavaScript - retrieve value from nested object, using array of keys Commented Oct 20, 2023 at 9:44
  • 1
    @T.J.Crowder just add the property Commented Oct 20, 2023 at 11:18

2 Answers 2

0

Thanks to the comments of T.J. Crowder and derpirscher I wrote a non-recursive function that solves the problem:

const path = 'requirements.general_info.aircraft.payload';
const modifiedJsonData = updateObject(jsonData, path, 'hg', 3000);

const updateObject = (json: any, path: string, unit: string, value: number): Object => {
  const pathKeys = path.split('.');

  if (allObjectPaths(json).includes(path)) {
    let temp = json;
    pathKeys.forEach((key: string) => {
      temp = temp[key];
    });
    temp['@_unit'] = unit;
    temp['#text'] = value;
    return json;
  } else {
    throw new Error('Path is incorrect');
  }
};
Sign up to request clarification or add additional context in comments.

Comments

-2

Try using lodash.

import _ from 'lodash'

function updateObject(json: any, path: _.PropertyPath, unit: string, value: number) {
  if (_.has(json, path)) {
    _.setWith(json, path, { '@unit': unit, '#text': value })
  }
  return json
}

let path = 'requirements.general_info.aircraft.payload'
// alternatively:
// path = ['requirements', 'general_info', 'aircraft', 'payload']
console.dir(updateObject(json, path, 'hg', 3000), { depth:null })

Remember to install lodash as well as its type definitions.

npm -i lodash
npm -i --save-dev @types/lodash

1 Comment

Works great (we won't get rid of Lodash that easily... :D)

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.