Replace All Keys of Deeply Nested Objects or Array of Objects in JavaScript

Change the case of object keys recursively to camel, snake, kebab, upper, lower, and start. Or modify in another way.

For a deeply nested object or array of objects, we might want to replace all the keys in some way, such as modifying their case (camel case, snake case, etc.) or adding an underscore at the start of each key or on both sides. Or we may like to change the keys in any other way.

Following is the generic JavaScript code and test object for that, followed by the complete code with specific examples:

The Generic Code

The code below is a generic function replaceAllObjKeys, to which we recursively pass obj and getNewKey parameters.

obj here could be a JavaScript object or array. The second parameter, getNewKey is a helper method. We need to decide what getNewKey method should be depending on how we need to change all the keys (capitalize, uppercase, lowercase, snake case, etc.).

const replaceAllObjKeys = (obj, getNewKey) => {

  if (Array.isArray(obj)) {
    for (let i = 0; i < obj.length; i++) {
      replaceAllObjKeys(obj[i], getNewKey);
    }
  }
  else if (typeof obj === "object") {
    for (const key in obj) {
      const newKey = getNewKey(key);
      obj[newKey] = obj[key];
      if (key !== newKey) {
        delete obj[key];
      }
      replaceAllObjKeys(obj[newKey], getNewKey);
    }
  }

  return obj;
};

Notice that once we get the new key, we assign it the reference of the existing value and delete the old key (deleting the key does not affect the value in any way as it’s just a memory reference).

Before deleting, we need to verify that the old and new keys are different because, in some cases, they might remain the same. For instance, when you change the key a_b_c to snake case, it’ll remain a_b_c. Deleting the key in such a case will remove the only key available, and the reference to its value will be lost.

The Test Object

For the specific examples below, I’ll be using the following test data:

const deeplyNestedObj = {
  id: 1,
  "a b C": {
    "d e f": {
      ghi: "ghi",
      jkL: "jkl"
    }
  },
  mno: [
    {
      onm: "onm"
    },
    {
      nOm: "nom"
    }
  ],
  "p q r": "pqr",
  Stu: {
    vwx: "vwx",
    y: {
      Z: "z"
    }
  }
};

Library Requirements

Instead of reinventing the wheel, I’m going to use the lodash library for most of the case changes. lodash is not strictly necessary. If you have your own implementation for key modification, you can pass it as getNewKey helper method. I’m using two small custom helper methods below startWithUnderscore and addUnderscoreOnBothSides.

Install lodash:

npm i lodash

And include the required methods in the code:

import {
  cloneDeep,
  capitalize,
  camelCase,
  kebabCase,
  snakeCase,
  startCase,
  upperCase,
  lowerCase,
  upperFirst,
  lowerFirst,
  toUpper,
  toLower,
} from "lodash";

(Here, cloneDeep is for not modifying the original example object before each subsequent call to replaceAllObjKeys, as I’m making multiple calls in the same example. It won’t be required for practical use.)

The reference to the methods used here can be found under “String” section in lodash’s docs.


The Complete Code

import {
  cloneDeep,
  capitalize,
  camelCase,
  kebabCase,
  snakeCase,
  startCase,
  upperCase,
  lowerCase,
  upperFirst,
  lowerFirst,
  toUpper,
  toLower,
} from "lodash";


const deeplyNestedObj = {
  id: 1,
  "a b C": {
    "d e f": {
      ghi: "ghi",
      jkL: "jkl"
    }
  },
  mno: [
    {
      onm: "onm"
    },
    {
      nOm: "nom"
    }
  ],
  "p q r": "pqr",
  Stu: {
    vwx: "vwx",
    y: {
      Z: "z"
    }
  }
}

const replaceAllObjKeys = (obj, getNewKey) => {

  if (Array.isArray(obj)) {
    for (let i = 0; i < obj.length; i++) {
      replaceAllObjKeys(obj[i], getNewKey);
    }
  }
  else if (typeof obj === "object") {
    for (const key in obj) {
      const newKey = getNewKey(key);
      obj[newKey] = obj[key];
      if (key !== newKey) {
        delete obj[key];
      }
      replaceAllObjKeys(obj[newKey], getNewKey);
    }
  }

  return obj;
};

const startWithUnderscore = (key) => `_${key}`;
const addUnderscoreOnBothSides = (key) => `_${key}_`;

console.log(
  "*** To Upper *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), toUpper),
  "\n\n"
);

console.log(
  "*** Upper Case *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), upperCase),
  "\n\n"
);

console.log(
  "*** Upper First *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), upperFirst),
  "\n\n"
);

console.log(
  "*** To Lower *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), toLower),
  "\n\n"
);

console.log(
  "*** Lower Case *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), lowerCase),
  "\n\n"
);

console.log(
  "*** Lower First *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), lowerFirst),
  "\n\n"
);

console.log(
  "*** Capitalize *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), capitalize),
  "\n\n"
);

console.log(
  "*** Camel Case *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), camelCase),
  "\n\n"
);

console.log(
  "*** Kebab Case *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), kebabCase),
  "\n\n"
);

console.log(
  "*** Snake Case *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), snakeCase),
  "\n\n"
);

console.log(
  "*** Start Case *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), startCase),
  "\n\n"
);

console.log(
  "*** Start With Underscore *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), startWithUnderscore),
  "\n\n"
);

console.log(
  "*** Add Underscore on Both Sides *** \n",
  replaceAllObjKeys(cloneDeep(deeplyNestedObj), addUnderscoreOnBothSides),
  "\n\n"
);

The Result

*** To Upper *** 
 {
  ID: 1,
  'A B C': { 'D E F': { GHI: 'ghi', JKL: 'jkl' } },
  MNO: [ { ONM: 'onm' }, { NOM: 'nom' } ],
  'P Q R': 'pqr',
  STU: { VWX: 'vwx', Y: { Z: 'z' } }
} 


*** Uppercase *** 
 {
  ID: 1,
  'A B C': { 'D E F': { GHI: 'ghi', 'JK L': 'jkl' } },
  MNO: [ { ONM: 'onm' }, { 'N OM': 'nom' } ],
  'P Q R': 'pqr',
  STU: { VWX: 'vwx', Y: { Z: 'z' } }
} 


*** Upper First *** 
 {
  Stu: { Vwx: 'vwx', Y: { Z: 'z' } },
  Id: 1,
  'A b C': { 'D e f': { Ghi: 'ghi', JkL: 'jkl' } },
  Mno: [ { Onm: 'onm' }, { NOm: 'nom' } ],
  'P q r': 'pqr'
} 


*** To Lower *** 
 {
  id: 1,
  mno: [ { onm: 'onm' }, { nom: 'nom' } ],
  'p q r': 'pqr',
  'a b c': { 'd e f': { ghi: 'ghi', jkl: 'jkl' } },
  stu: { vwx: 'vwx', y: { z: 'z' } }
} 


*** Lowercase *** 
 {
  id: 1,
  mno: [ { onm: 'onm' }, { 'n om': 'nom' } ],
  'p q r': 'pqr',
  'a b c': { 'd e f': { ghi: 'ghi', 'jk l': 'jkl' } },
  stu: { vwx: 'vwx', y: { z: 'z' } }
} 


*** Lower First *** 
 {
  id: 1,
  'a b C': { 'd e f': { ghi: 'ghi', jkL: 'jkl' } },
  mno: [ { onm: 'onm' }, { nOm: 'nom' } ],
  'p q r': 'pqr',
  stu: { vwx: 'vwx', y: { z: 'z' } }
} 


*** Capitalize *** 
 {
  Stu: { Vwx: 'vwx', Y: { Z: 'z' } },
  Id: 1,
  'A b c': { 'D e f': { Ghi: 'ghi', Jkl: 'jkl' } },
  Mno: [ { Onm: 'onm' }, { Nom: 'nom' } ],
  'P q r': 'pqr'
} 


*** Camelcase *** 
 {
  id: 1,
  mno: [ { onm: 'onm' }, { nOm: 'nom' } ],
  aBC: { dEF: { ghi: 'ghi', jkL: 'jkl' } },
  pQR: 'pqr',
  stu: { vwx: 'vwx', y: { z: 'z' } }
} 


*** Kebabcase *** 
 {
  id: 1,
  mno: [ { onm: 'onm' }, { 'n-om': 'nom' } ],
  'a-b-c': { 'd-e-f': { ghi: 'ghi', 'jk-l': 'jkl' } },
  'p-q-r': 'pqr',
  stu: { vwx: 'vwx', y: { z: 'z' } }
} 


*** Snakecase *** 
 {
  id: 1,
  mno: [ { onm: 'onm' }, { n_om: 'nom' } ],
  a_b_c: { d_e_f: { ghi: 'ghi', jk_l: 'jkl' } },
  p_q_r: 'pqr',
  stu: { vwx: 'vwx', y: { z: 'z' } }
} 


*** Startcase *** 
 {
  Stu: { Vwx: 'vwx', Y: { Z: 'z' } },
  Id: 1,
  'A B C': { 'D E F': { Ghi: 'ghi', 'Jk L': 'jkl' } },
  Mno: [ { Onm: 'onm' }, { 'N Om': 'nom' } ],
  'P Q R': 'pqr'
} 


*** Start With Underscore *** 
 {
  _id: 1,
  '_a b C': { '_d e f': { _ghi: 'ghi', _jkL: 'jkl' } },
  _mno: [ { _onm: 'onm' }, { _nOm: 'nom' } ],
  '_p q r': 'pqr',
  _Stu: { _vwx: 'vwx', _y: { _Z: 'z' } }
} 


*** Add Underscore on Both Sides *** 
 {
  _id_: 1,
  '_a b C_': { '_d e f_': { _ghi_: 'ghi', _jkL_: 'jkl' } },
  _mno_: [ { _onm_: 'onm' }, { _nOm_: 'nom' } ],
  '_p q r_': 'pqr',
  _Stu_: { _vwx_: 'vwx', _y_: { _Z_: 'z' } }
} 




See also

When you purchase through links on techighness.com, I may earn an affiliate commission.