Retrieve the complete paths for the keys within a deeply nested object in real-time

Trying to dynamically retrieve the keys of a nested object is proving to be quite challenging. Take for instance this sample object:

{
    ts: "2021-05-06T11:06:18Z",
    pr: 94665,
    pm25: 5,
    co2: 1605,
    hm: 32,
    m: {
      isConnected: true,
      wifidBm: 0,
    },
    pm1: 5,
    s: {
      "0": {
        runningTime: 0,
        sn: "05064906137109790000",
        wearRate: 0,
        enabled: true,
        co2: 1605,
      },
      "1": {
        enabled: false,
        sn: "125630092251006",
      },
      "2": {
        enabled: false,
        sn: "05064906137109450000",
      },
      "3": {
        fanStatus: 0,
        pm25: 5,
        pm1: "5",
        e: {
          rawSensorError: 0,
        },
        pm10: 5,
        runningTime: 0,
        sn: "125630100924141",
        wearRate: 0,
        enabled: true,
      },
    },
    id: "avo_jggv6bsf211",
    tp: "20.6",
    pm10: 5,
    type: "monitor",
  }

An example of the desired output would be:

str = 'ts, pr, pm25, co2, hm, "m.isConnected, m. wifiBm, pm1, s.0.runningTime, s.0.sn, ...' 

The current code snippet in use:

guessHeader(object: MeasurementModel | any, parentKey?: string): string[] {
    // Looping on object's keys
    Object.keys(object).forEach(key => {
      if (typeof object[key] === 'object' && key !== 'ts') {
        // If the object is an array recurse in it
        return this.guessHeader(object[key], key)
      } else {
        // If we have a parentKey keep header as
        if (parentKey)
          this.header.push(`${parentKey}.${key}`)
        else
          this.header.push(key)
      }
    })
    return this.header
  }

While it works for the key "m," providing "m.isConnected" and "m.wifiBm," there are issues with keys like "s.0.runningTime," where only "0.runningTime" is returned. Given that the object structure may change and become even more complex, it is crucial to find a solution that accommodates all scenarios. Attempts to save the keys in an array for later parsing have thus far been unsuccessful.

Answer №1

The problem lies right here:

// If the object is an array, iterate through it
return this.guessHeader(object[key], key)

Instead, it should be:

this.header.push(...this.guessHeader(object[key], parentKey === undefined ? key : `${parentKey}.${key}`))

It's worth noting that typeof null === 'object', so ensure to check if object[key] is not null (e.g.

typeof object[key] === 'object' && object[key]
) before passing it to guessHeader.

Additionally, MeasurementModel | any is equivalent to any. It's better to avoid using any and follow this advice from using unknown instead, as it provides type safety.

An example implementation of guessHeader could resemble the following code snippet:

guessHeader(object: object, parentKey?: string): string[] {
  Object.keys(object).forEach(key => {
    const newKey = parentKey === undefined ? key : `${parentKey}.${key}`
    const value = (object as Record<string, unknown>)[key]
    if (typeof value === 'object' && value && key !== 'ts')
      this.header.push(...this.guessHeader(value, newKey))
    else
      this.header.push(newKey)
  })
  return this.header
}

Personally, leveraging Object.entries and adopting a method like shown below might prove advantageous:

const guessHeader = (object: object, acc = ''): string =>
  Object.entries(object)
    .map(([key, value]: [string, unknown]) =>
      // To prevent recursion into the ts key,
      // compared for key !== 'ts'
      // Speculating that ts could be associated with Date; you could exclude recursion into all Dates by validating
      // typeof value == 'object' && value && !(value instanceof Date)
      key !== 'ts' && typeof value === 'object' && value
        ? guessHeader(value, `${acc}${key}.`)
        : acc + key
    )
    .join(', ')

const input = {ts: '2021-05-06T11:06:18Z', pr: 94665, pm25: 5, co2: 1605, hm: 32, m: {isConnected: true, wifidBm: 0}, pm1: 5, s: {0: {runningTime: 0, sn: '05064906137109790000', wearRate: 0, enabled: true, co2: 1605}, 1: {enabled: false, sn: '125630092251006'}, 2: {enabled: false, sn: '05064906137109450000'}, 3: {fanStatus: 0, pm25: 5, pm1: '5', e: {rawSensorError: 0}, pm10: 5, runningTime: 0, sn: '125630100924141', wearRate: 0, enabled: true}}, id: 'avo_jggv6bsf211', tp: '20.6', pm10: 5, type: 'monitor'}

// same as above code block
const guessHeader = (object, acc = '') => Object.entries(object).map(([key, value]) => key !== 'ts' && typeof value === 'object' && value ? guessHeader(value, `${acc}${key}.`) : acc + key).join(', ')

console.log(guessHeader(input))

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

Replace the value of a react-text attribute using an external JavaScript file

I am currently developing a plugin for the popular messaging app, Discord. My goal is to modify the text displayed in between user names, specifically changing "and" and "are typing..." as illustrated in the code snippet below. <span class="text"> ...

Is it beneficial to utilize jQuery ahead of the script inclusions?

While working on a PHP project, I encountered a situation where some parts of the code were implemented by others. All JavaScript scripts are loaded in a file called footer, which indicates the end of the HTML content. This presents a challenge when tryi ...

Error encountered with Firebase when integrating Firestore into a NextJS application

For my project, I have successfully implemented authentication using Firebase. However, when I attempt to use Firestore in my app, I encounter an error prompting me to initialize my app. I already have a file for this purpose where I import all the necessa ...

React-beautiful-dnd does not function properly when used with the overflow auto property

Currently, I'm in the process of developing an application similar to "Trello" and have encountered a few challenges along the way. I've successfully created the main components such as the "Board," "Cards," and "Tasks." Each card has a fixed wid ...

Issue with JavaScript variables (I presume) - there seems to be a conflict when one variable is used alongside another

I am attempting to conduct a test that requires displaying the number of attempts (each time the button is pressed) alongside the percentage of successful attempts, updating each time the button is clicked. However, I've encountered an issue where onl ...

Tips for transferring a variable from Next.js to a plain JavaScript file

When it comes to Canvas Dom operations in my NextJs file, I decided to include a Vanilla JS file using 'next/script'. The code for this is: <Script id="canvasJS" src="/lib/canvas.js" ></Script>. Everything seems to ...

Dealing with Restangular errors: a guide on sending a custom object to a controller unaware of Restangular

I'm facing a challenge with my current approach, possibly due to my limited understanding of Angular promises versus Restangular promises. I have developed an AngularJs application using TypeScript, although the usage of TypeScript is not crucial in t ...

Error encountered while utilizing Array.find with a specific data type

I am trying to locate the user's browser language from a list of supported languages. Here is the code snippet I am using: const userLanguage = browserLanguages.find(language => !!supported[language]); But unfortunately, I'm encountering thi ...

Having trouble figuring out what is causing non-serializable error in Redux (Redux error)

Initially, my react-native application was functioning smoothly and this particular page (screen) had been developed and working perfectly. However, out of the blue, it has started to encounter an error related to non-serializable data in the 'save_re ...

The Ajax response is not providing the expected HTML object in jQuery

When converting HTML data from a partial view to $(data), it's not returning the jQuery object I expected: console.log($(data)) -> [#document] Instead, it returns this: console.log($(data)) -> [#text, <meta charset=​"utf-8">​, #text ...

How can I prevent Chrome from constantly prompting for permission to access the camera?

I have been working on some HTML/JavaScript/WebRTC projects that involve using the webcam. Despite hosting the files from my local web server (127.0.0.1), Chrome always prompts me for permission to access the camera each time I reload the page. Is there a ...

Is there a secure method to create a Bitcoin private key directly through a web browser?

Is it possible to create a truly random bitcoin private key without depending on third-party libraries like ECPair or tiny-secp256k1? An alternative method for generating a secure random key is as follows: import ECPairFactory from 'ecpair' impo ...

Guide to including configuration settings in locals for Sails.js

Currently working on a webapp with Sails.js, I am looking for ways to set up different configurations for development and production modes. Initially, I attempted to store the configuration key in config/local.js, but unfortunately, it did not yield the de ...

Executing form validation upon submission of a form from the view in BackboneJS

Recently, I delved into using Backbone.js to organize my JavaScript code and create modular applications. However, I encountered a snag when dealing with events. My goal is to develop a simple View that can handle forms and validate them. Eventually, I pl ...

sending the express application to the route modules

Currently, I am developing an express 4 api server with no front end code. Rather than structuring my project based on file types such as routes and models, I have decided to organize it around the business logic of the project. For example, within my Use ...

When is the AbortSignal in the TanStack useQuery function considered as undefined?

The TanStack React Query documentation (visit here) provides insights on utilizing the queryFn property with an object containing a signal property for query cancellation. Check out this example: const query = useQuery({ queryKey: ['todos'], ...

Combining various data entries within a unified form

I have a requirement to create a user-friendly page for entering multiple sets of personal information. Users should be able to fill out details for each record separately and then submit all the records at once. My goal is to design the page in such a wa ...

Error encountered when trying to generate a collection from JSON using Backbone framework

jQuery(function() { var Hotel = Backbone.Model.extend({ defaults: { idHotel:"", hotelName:"Grand Marina", hotelAddress:"Lakeview Drive", hotelStars:"4", hotelRoomsCount:"180", ...

Steps to Transform String Array into Prisma Query Select Statement

I have a requirement to dynamically select Prisma columns based on client input: ['id', 'createdAt', 'updatedAt', 'Order.id', 'Order.Item.id', 'Order.Item.desc'] The desired format for selection ...

Trick to trigger a redraw in reactJS?

How can I update my table using an ajax call and ensure that the new data is displayed in the datatable? var GridRow = React.createClass({ render: function() { var data = [], columns; if(this.props.columns){ for(var i = ...