Combining keys from an array of objects into a single array categorized by key names

When working with an array of objects, I need to filter and extract all the keys. One challenge I face is when there are nested objects, I want to concatenate the key names to represent the nested structure. For example:

const data = [ id: 5, name: "Something", obj: { lower: True, higher: False } ]
result = ["id", "name", "obj.lower", "obj.higher"]

I have been able to accomplish the above code, but when there are multiple nested objects within the data, I find myself adding more if conditions in my logic. I'm seeking a better way to handle this, so that regardless of the number of nested objects, the concatenation happens seamlessly.
The code snippet I used for the above scenario:

const itemsArray = [
      { id: 1, item: "Item 001", obj: { name: 'Nilton001', message: "Free001", obj2: { test: "test001" } } },
      { id: 2, item: "Item 002", obj: { name: 'Nilton002', message: "Free002", obj2: { test: "test002" } } },
      { id: 3, item: "Item 003", obj: { name: 'Nilton003', message: "Free003", obj2: { test: "test003" } } },
    ];

const csvData = [    
    Object.keys(itemsArray[0]),
    ...itemsArray.map(item => Object.values(item))
].map(e => e.join(",")).join("\n")

// Separating keys
let keys = []
const allKeys = Object.entries(itemsArray[0]);
for (const data of allKeys) {
    if (typeof data[1] === "object") {
        const gettingObjKeys = Object.keys(data[1]);
        const concatingKeys = gettingObjKeys.map((key) => data[0] + "." + key);        
        keys.push(concatingKeys);
    } else {
        keys.push(data[0])
    }
}

//Flating
const flattingKeys = keys.reduce((acc, val: any) => acc.concat(val), []);

My goal is to extract all the keys from the first object in the array. If there are nested objects, I want to concatenate the object names to represent the hierarchy.

const data = 
[
   { id: 10, obj: {name: "Name1", obj2: {name2: "Name2", test: "Test"}}}
   ...
]

Final result = ["id", "obj.name", "obj.obj2.name2", "obj.obj2.test"]

Note: The first object includes all the keys needed, no further looping required to fetch KEYS.

My objective is to extract all keys from the initial object in the array. When encountering nested objects, I want to concatenate the object names (e.g., obj.obj2key1).

Answer №1

To extract the keys from nested objects, you can map through the objects.

const
    getKeyValues = object => Object
        .entries(object)
        .flatMap(([k, v]) => v && typeof v === 'object'
            ? getKeyValues(v).map(s => `${k}.${s}`)
            : k
        ),
    getValues = object => Object
        .entries(object)
        .flatMap(([k, v]) => v && typeof v === 'object'
            ? getValues(v)
            : v
        ),
    data = { id: 1, item: "Item 001", obj: { name: 'Nilton001', message: "Free001", obj2: { test: "test001" } } },
    keys = getKeyValues(data),
    values = getValues(data);

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

Answer №2

an example like so

const itemsArray = [
      { id: 1, item: "Item 001", obj: { name: 'John Doe', message: "Hello World", obj2: { test: "test001" } } },
      { id: 2, item: "Item 002", obj: { name: 'Jane Doe', message: "Goodbye World", obj2: { test: "test002" } } },
      { id: 3, item: "Item 003", obj: { name: 'Alice', message: "Wonderland", obj2: { test: "test003" } } },
    ];
    
const item = itemsArray[0];

const getAllKeys = (obj, prefix=[]) => {
 if(typeof obj !== 'object'){
   return prefix.join('.')
 }
 return Object.entries(obj).flatMap(([k, v]) => getAllKeys(v, [...prefix, k]))
}

console.log(getAllKeys(item))

Answer №3

The original poster's solution could be made more concise by introducing a prefix parameter (representing the parent key) and a results parameter (initialized as [] and fed into the recursive function) for the purpose of flattening the data...

let data = { key0: 'value0', key1: { innerKey0: 'innerValue0', innerInner: { deeplyNested: 'value' } }, key2: { anotherInnerKey: 'innerValue' } }

function extractKeys(prefix, data, result=[]) {
  let keys = Object.keys(data);
  keys.forEach(key => {
    if (typeof data[key] === 'object')
      extractKeys(key, data[key], result);
    else
      result.push(`${prefix}.${key}`)
  });
  return result;
}

console.log(extractKeys('', data))

Answer №4

function collectObjectKeys(object) {
  return Object.keys((typeof object === 'object' && object) || {}).reduce((accumulator, key) => {
    if (object[key] && typeof object[key] === 'object') {
      const keys = collectObjectKeys(object[key]);
      keys.forEach((k) => accumulator.add(`${key}.${k}`));
    } else {
      accumulator.add(key);
    }
    return accumulator;
  }, new Set());
}

// Gather all keys from items in an array and store them in a set
const keysSet = itemsArray.reduce(
  (accumulator, item) => new Set([...accumulator, ...collectObjectKeys(item)]),
  new Set()
);

console.log('Object Keys => ', Array.from(keysSet));

Answer №5

To implement recursion in this scenario, verify that the type of [1,3,5] equals object. Additionally, ensure that the variable value is not an array by checking !Array.isArray(value):

const sampleObj = { id: 10, details: {name: "Name1", addInfo: {info: "Info1", test: "Test"}}};

const extractKeys = (obj, prefix) => Object.entries(obj).flatMap(([key, value]) => 
    typeof(value) === 'object' && !Array.isArray(value) ? 
        extractKeys(value, (prefix ? `${prefix}.` : "") + key) : 
        (prefix ? `${prefix}.` : "") + key
);

console.log( extractKeys(sampleObj) );

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

Is there still a need to preload dynamic images in the background?

Imagine you have HTML code that includes an image with a placeholder: <img class="lazy-load" src="http://via.placeholder.com/150/?text=placeholder" data-src="http://via.placeholder.com/150/?text=real%20image"/> At some stage, you want to implem ...

Fade out the div element when clicked

For my game project, I needed a way to make a div fade out after an onclick event. However, the issue I encountered was that after fading out, the div would reappear. Ideally, I wanted it to simply disappear without any sort of fade effect. Below is the co ...

What steps should I follow to bring in an animated SVG file into Next.js 13 without losing transparency and animation effects?

How to Include an Animated SVG File in Next.js 13 import Image from "next/image"; export default function Home() { return ( <main className="flex h-screen flex-col items-center"> <div className="container mt-1 ...

Is there a way to display tiff files in Google Chrome?

I've been struggling with this problem for over 48 hours now, tirelessly searching for a solution. The issue lies within an application built using the ext.net framework on the front end. Specifically, I'm encountering difficulties when it comes ...

The code functions properly on a standalone device, however, it encounters issues when

I am facing an issue with my JavaScript code. It works perfectly fine when I run it on my local machine, but once I upload it to the server, it only functions properly after I refresh the page. Below is the code in question. Please do not hesitate to rea ...

Learn how to display two different videos in a single HTML5 video player

Seeking a solution to play two different videos in one video element, I have found that only the first source plays. Is jQuery the answer for this problem? HTML Code: <video autoplay loop id="bbgVid"> <source src="style/mpVideos/mpv1.mp4" type ...

What is the best way to display the value of a PHP variable in a JavaScript pop-up window?

Here are the scripts I have. A user will input a numerical value like 123 as a parameter in the URL, and the application will retrieve that value from MySQL and display it in the textarea. For example, if you enter "example.com/index.php?id=123" in the UR ...

Navigating the complexities of integrating Angular-based JS select/input values using CefSharp Offscreen on an external website: A comprehensive guide

I have encountered some challenges with setting input values on a third-party webpage that utilizes Angular for field validation. When attempting to set the value attribute using Chrome or CefSharp, the value does not update as expected. To work around th ...

Preventing Express.JS HTTP requests from being blocked by npm cron

I'm experimenting with the cron module from npm within my Express.js application. The structure of my app is quite straightforward. I have a function to establish a connection to the database, where I then register all the different modules that hand ...

Transmit parameters via onclick event on FullCalendar

I have been utilizing the full calendar feature and it's been functioning properly. However, I am encountering an issue with sending parameters via onclick event. Below is the JavaScript code that I currently have: <script> $(document).ready(fu ...

"Troubleshooting the issue with the @click event failing to update the data

Working in Vue.js, my v-for loop is set up to go through a list and generate buttons. Each button has a click event that should change the value of upUrl to its index: <div class="mt-3" v-for="(buttonPic, index) in buttonPics" ...

Exploration of features through leaflet interaction

Attempting to plot bus routes on a map using leaflet with geojson for coordinates. Facing issues with making the bus line bold when clicked, and reverting the style of previously clicked features back to default. Current Progress function $onEachFeature( ...

Creating a rotating wheel using JavaScript that is activated by a key press event

I need some help with implementing a keystroke event in this code so that the spinning wheel can start based on a key press, like the spacebar. Any suggestions on how to achieve this? I have found an event code for keystrokes in JavaScript: document.body. ...

How can I change the color of a designated column in a Google stacked bar chart by clicking a button?

I am in the process of creating a website that compares incoming students at my university across different academic years. We have successfully implemented a pie chart to display data for the selected year. Now, we aim to include a stacked bar chart next ...

Guide to inputting text into the Dev element

I am encountering a challenge with automating gist creation on GitHub. The issue arises when trying to input text into the gist content-box (see attached image). Despite attempting to use Javascript executer, I have not been successful. JavascriptExecutor ...

In what way can a container impact the appearance of a child placed in the default slots?

Visiting the vue playground. The main goal is for the container component to have control over an unspecified number of child components in the default slot. In order to achieve this, it's assumed that each child component must either hold a propert ...

Ensure that the search input field is in focus whenever the showSearch state is true

Having difficulty focusing on the input field whenever the showSearch state is true. Utilizing useRef and useEffect for this purpose. When the showSearch flag changes, the useEffect hook is triggered to check if showSearch is true, and if so, it should foc ...

Develop a responsive shopping cart using PHP and JavaScript

I am in the process of developing an ePos system that allows users to add items to their basket by simply clicking on them, and then calculates the total price without needing to refresh the entire page. I initially attempted to use $_SESSION and store th ...

Is it possible to combine Ajax, JS, HTML, PHP, and MySQL in a single project?

I am looking to create a web application and wondering if I can integrate Ajax, JavaScript, HTML, PHP, and MySQL all together? ...

Forming a JSON structure using input variables

Currently, I am attempting to construct a JSON object using variables extracted from a form. var firstName = $('#firstName').val(); var lastName = $('#lastName').val(); var phone = $('#phoneNumber').val(); var address ...