Restructure the array of objects or nested objects into the desired format

I am currently working on transforming an array object into a new object, where some keys are renamed and the rest of the keys are converted to camelCase.

For example:

1. Renaming Keys

The key orgId will be renamed to clientDivisionOrganizationId.

2. Converting Key Cases

All other keys will be converted from snake_case to camelCase, except for a specific scenario with nested arrays like address_usages, which presents a unique challenge for conversion.

I have explored various solutions but would greatly appreciate any help or insights.

Thank you

const originalArray =[{
    // array contents here
}];
// define transformation rules
const newKeyMap={
    // key mappings here
};
function camelize(text) {
    // function logic for camelize
}

// function to transform array object using defined rules
const transformArrayObject=(originalArray, newKeyMap)=>{
    return originalArray.map(obj => {
        const transformedObj = Object.entries(obj).reduce((acc, [key, value]) =>{
            if (typeof value === "object" && !Array.isArray(value) && value!==null) {
                const nestedObj = Object.entries(value).reduce((nestedAcc, [nestedKey, nestedValue]) =>{
                    const newNestedKey = newKeyMap[`${camelize(key)}.${camelize(nestedKey)}`] || camelize(nestedKey);
                    nestedAcc[camelize(newNestedKey)] = nestedValue;
                    return nestedAcc;
                }, {});
                acc[camelize(key)] = nestedObj;
            } else if (Array.isArray(value) && value.length>0) {
                acc[camelize(key)] = value.map(nestedObj =>{
                    return Object.entries(nestedObj).reduce((nestedAcc, [nestedKey, nestedValue]) =>{
                        const newNestedKey = newKeyMap[`${key}.${camelize(nestedKey)}`] || nestedKey;
                        nestedAcc[camelize(newNestedKey)] = nestedValue;
                        return nestedAcc;
                    }, {});
                });
            } else {
                    const newKey = newKeyMap[camelize(key)] || camelize(key);
                    acc[newKey] = value;
            }
            return acc;
        }, {});
        return transformedObj;
    });
}
console.log("Result:",transformArrayObject(originalArray,newKeyMap));

Answer №1

Regrettably, I must confess that I find it a bit challenging to decipher your initial code. However, employing recursion could be the key to handling the nested objects effectively. While your current transformation is almost there, you also need to convert the values of the object entries. To simplify this process, it might be beneficial to create a separate function for organizing the code.

function translate(value, keyMap, prefix="") {
  // Recursively transform the keys within the given value.

  if (Array.isArray(value)) {
    // Use the prefix as is for array entries
    return value.map(val => translate(val, keyMap, prefix));
  }
  else if (value && typeof value === "object") {
    // The bulk of the work happens here...
    return Object.entries(value).reduce((acc, [nestedKey, nestedValue]) => {
      const newNestedKey = keyMap[`${prefix}${nestedKey}`] || camelize(nestedKey);
      // Update the prefix with the new key while recursing
      const newPrefix = `${nestedKey}.`;
      acc[newNestedKey] = translate(nestedValue, keyMap, newPrefix);
      return acc;
    }, {});
  }
  else {
    // Simple scenario -- non-object/non-array value, just return it unchanged
    return value;
  }
}

// Customize key names by concatenating using `.`
// (Note: some entries in the original map were redundant)
const updatedKeyMap={
    "name":"siteName",
    "study_environment_uuid":"studyEnvironmentuuid",
    "team_memberships_count":"teamMembershipCount",
    "org_id":"clientDivisionOrganizationId",

    // Extraneous example to illustrate nesting
    "main_address.timezone_name": "timezone_name"
};

function camelize(text) {
    const transformed = text.toLowerCase()
        .replace(/[-_\s.]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
    return transformed.substring(0, 1).toLowerCase() + transformed.substring(1);
}

const inputArray =[{
    "uuid": "65a49008-91ba-4dc6-8fd8-476c4ea7b84d",
    "name": "Post-man Hospital-local",
    "site_number": "PKKk-2219232",
    ...
}];

const modifiedArray = translate(inputArray, updatedKeyMap);
console.log("Final Output:", modifiedArray);

Answer №2

If you want to efficiently check a property with new keys, one option is to utilize a recursive approach where you can pass the path to the property for evaluation.

const
    originalData = [{ id: "65a49008-3291ba-4dc6-8fd8-476c4ea7b84d", title: "Post-man Hospital-local", number: "PKKk-2219232", phone: "", fax: "", org_id: "PKKKK-2219232", investigator: { id: null, email: null, first_name: null, last_name: null }, licenses: [], has_users: false, locations: [{ id: "60c132a43b-5ab5-434a91-a4ec-d6e4704d4937", address_1: "Chinchwad", address_2: "", city: "Pune", state: "MH", country: "IND", postal_code: "412105", latitude: "18.64742", longitude: "73.80003", timezone: "Asia/Kolkata", types: ["main"] }], emails: [], telecoms: [], status: "planned", team_count: 0, addresses: [{ id: "e58efc53223a-2028-4f7a-bc56-e8d72f4f2c18", active: true, types: ["main"], location: { id: "60c123a43b-5ab5-4a91-a4ed6e4704d4937", address_1: "Chinchwad", address_2: "", city: "Pune", state: "MH", country: "IND", postal_code: "412105", latitude: "18.64742", longitude: "73.80003", timezone: "Asia/Kolkata" } }], pi_tm: null, main_location: { address_1: "Chinchwad", address_2: "", city: "Pune", state: "MH", country: "IND", postal_code: "412105", latitude: "18.64742", longitude: "73.80003", timezone: "Asia/Kolkata" }],
    newKeysMap = { id: "id#", number: "number#", title: "title#", main_location: "mainLocation#", "main_location.address_1": "address1#", "main_location.address_2": "address2#", "main_location.city": "city#", "main_location.state": "state#", "main_location.country": "country#", "main_location.postal_code": "postalCode#", environment_id: "envId#", team_count: "teamCount#", has_users: "usersFlag#", divisionId: "orgId#" },
    camelizeText = text => {
        const a = text.toLowerCase().replace(/[-_\s.]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
        return a.substring(0, 1).toLowerCase() + a.substring(1);
    },
    getKeyName = (key, path = '') => path + (path && ".") + key,
    transformObject = (keys, path = "") => obj => {
        const transformedObject = Object.entries(obj).reduce((acc, [key, value]) => {
            const newKey = keys[getKeyName(key, path)] || camelizeText(key);
            if (Array.isArray(value)) acc[newKey] = transformArrayObject(value, keys);
            else if (value && typeof value === "object") acc[newKey] = transform(keys, getKeyName(key, path))(value);
            else acc[newKey] = value;
            return acc;
        }, {});
        return transformedObject;
    },
    transformArrayObject = (originalData, newKeysMap) => originalData.map(transformObject(newKeysMap)),
    endResult = transformArrayObject(originalData, newKeysMap);

console.log(endResult);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A guide on converting a JSON array into CSV format while customizing attributes

I'm currently developing a Node.js application using JavaScript. I have an array that I need to convert into a CSV format with specific attributes. var data = [ { "Name":"nom1", "Division":"first", "Cities":['city1','c ...

I'm curious about the origin and purpose of req.user - where does it come from and

Recently, I've been delving into Nestjs and found myself a bit puzzled by the req.user. Where does this come from and do we have to manually request it? What exactly is req.user and what advantages does it offer? Must I assign payload to it manually? ...

Navigating up and down effortlessly using bootstrap

My webpage has a collapsible form located near the bottom, but when it's opened users must scroll down to see all of it. Is there a way to automatically scroll down when it's opened and then scroll back up when closed? Take a look at my code: & ...

importing with a specific name may result in errors, while importing everything with * from does not

Exploring the directory layout of features within my react application: feature1 actions actionTypes.js crud.js component.js container.js reducer.js sagas.js sagas.test.js services.js index.js feature2 ...

In JavaScript, the mousedown event consistently receives the "e" parameter as the event object

I am facing an issue while trying to handle a middle mouse button click event using JQuery on a DataTable from the website https://datatables.net/. Below is the code I have implemented. var tbl = document.getElementById("entries"); $(tbl).on('mousedo ...

What is the process of removing a document with Next.JS and MongoDB by utilizing next-connect?

Currently in the process of constructing my first CRUD application using NextJS/Mongodb and I've decided to utilize next-connect for handling the methods. As a newcomer to this field, I have managed to successfully create posts and update user profile ...

Updating Bootstrap Indicators with jQuery on Click Event

Unfortunately, I am unable to share an image due to limited internet data. My goal is to switch each image to its sprite equivalent. There are three list items that I'm struggling to change because they each have two classes that need to be updated. ...

Forming a distinct array from a collection of objects

Describing demoList: demoList = [ { id: 1, validFrom: "2019-06-01T00:00:00", validTo: "2020-06-17T00:00:00", xxxM: 50, xxxN: 2.2, xxxQ45: 2, xxxQ100: 1.65, xxxQ125: null, xxxQ150: null, xxxQ2 ...

Playing videos directly within Facebook's Instant Articles on iPhones

Currently, I'm facing an issue with embedding a video in a Facebook Instant Article using an iframe. When attempting to play the video on an Android device, it plays within the article content instead of going full-screen. However, if I try to view ...

What is the process for extracting information from one table based on a column's data in another table?

Let's consider two tables: Table 1 id | email 1 | email1 2 | email2 Table 2 userid | username 2 | user1 3 | user2 Now, with the help of sails.js associations, here is what I aim to achieve: I have a username = user1. What I need to a ...

Generating a PHP array by parsing a text file with space-separated values

I have a text file containing directories that I want to convert into an array in PHP. The challenge is that the items are space delimited, but the number of spaces varies and there are spaces within directory names. I am looking for a way to parse this te ...

The "checked" property is absent in the ASP.NET checkbox within the gridview

In my asp.net gridview control, the checked property seems to be missing. I am trying to access the checked property using jquery Gridview structure: <Columns> <asp:TemplateField> <ItemTemplate> ...

Understanding the functionality of AngularJS UI-Router

I'm trying to wrap my head around the purpose of the parent attribute within the state directive in UI-Router. Let's consider this code snippet: $stateProvider .state('base', { abstract: true, url: '', templateU ...

Ordering and displaying data with AngularJS

Trying to maintain a constant gap of 5 between pagination elements, regardless of the total length. For instance, with $scope.itemsPerPage = 5 and total object length of 20, we should have 4 pages in pagination. However, if $scope.itemsPerPage = 2 and tota ...

Ways to preserve decal placement using Three.js

I am searching for a solution to store and reload the decals generated in this example (source code). The goal is to allow users to save a new splatter they paint and then reload it at a later time. I have attempted various methods, but none have been succ ...

How to Retrieve the Name of the Active Element from an Unordered List (<ul>) in ReactJS and Display it in the

I have a project where I am creating a long navbar specifically for mobile devices, and I am structuring it in an accordion style. Initially, the view will show the currently active link name. When the user clicks on this active link name, it expands below ...

Is it wrong to use <match v-for='match in matches' v-bind:match='match'></match>? Am I allowed to incorporate the match variable from the v-for loop into the v-bind attribute on the

I am attempting to display HTML for each individual match within the matches array. However, I am uncertain if <match v-for='match in matches' v-bind:match='match'></match> is the correct syntax to achieve this. To clarify, ...

Ways to update a div periodically with new data fetched from a file - Here's How!

I am looking to auto-refresh a specific div every few seconds on my index.php page below. <?php session_start(); if (! check_write()) { redirect('testlogin.php'); return; } if (file_exists('lmt.json')) { $lmt = json_de ...

Convert a string consisting of double values separated by commas into an array of double values using Java 8

Looking to convert a String containing double values into a double array? Here's an example: String str = "0.1,0.4,0.9,0.1"; You can achieve this by doing the following: double[] arr = {0.1, 0.4, 0.9, 0.1}; While one common way to do this is by us ...

Transmitting an item through a GET request using parameters in Postman

Recently joining this site, I created my user account just a few days back. I am attempting to send a GET request using Postman, but it's not working as expected. There seems to be some issue. Here is what I am trying to accomplish: Using Postman: ...