Explore and adjust the contents of a complex and nested JavaScript object

In my dataset, there are objects nested deeply with arrays, objects within arrays, and so on.

Each nested object includes a property called sys, which contains another property called id.

I have a list of specific id values that I want to remove from the original object. How can I recursively loop through the entire structure and adjust it to exclude these unwanted values?

For instance, consider the following data:

let data = {
  sys: {
    id: '1'
  },
  items: [
    {
      sys: {
        id: '2'
      },
      fields: {
        title: 'Item title',
        sponsor: {
          sys: {
            id: '3'
          },
          fields: {
            title: 'Sponsor Title'
          }
        },
        actions: [
          {
            sys: {
              id: '4'
            },
            fields: {
              title: 'Google',
              url: 'google.com'
            }
          },
          {
            sys: {
              id: '5'
            },
            fields: {
              title: 'Yahoo',
              url: 'yahoo.com'
            }
          }
        ]
      }
    }
  ]
}

And here is an array of id's to delete:

const invalidIds = ['3', '5'];

After running the function, the resulting object should have the property with sys.id of '3' set to null, while the object with sys.id of '5' should be removed entirely from its containing array:

// Expected Output:
{
  sys: {
    id: '1'
  },
  items: [
    {
      sys: {
        id: '2'
      },
      fields: {
        title: 'Item title',
        sponsor: null,
        actions: [
          {
            sys: {
              id: '4'
            },
            fields: {
              title: 'Google',
              url: 'google.com'
            }
          }
        ]
      }
    }
  ]
}

Utilizing guidance from this solution, I am able to recursively search throughout the object and its nested arrays:

const process = (key, value) => {
  if (typeof value === 'object' && value.sys && value.sys.id && invalidIds.includes(value.sys.id)) {
    console.log('found one', value.sys.id);
  }
};

const traverse = (obj, func) => {
  for (let key in obj) {
    func.apply(this, [key, obj[key]]);

    if (obj[key] !== null) {
      if (typeof obj[key] === 'object') {
        traverse(obj[key], func);
      } else if (obj[key].constructor === Array) {
        obj[key].map(item => {
          if (typeof item === 'object') {
            traverse(item, func);
          }
        });
      }
    }
  }
};

traverse(data, process);

However, I am struggling to properly alter the array. Furthermore, I would prefer to create a completely new object rather than modifying the existing one to maintain immutability.

Answer №1

These are the key insights that guided me towards my solution:

  1. In order to create a new object, it is necessary to include the return statement within your function.
  2. When removing items from an array, remember to filter out valid items first and then recursively call the traverse function on them.
  3. The condition typeof obj[key] === 'object' will return true for Arrays as well, making the subsequent else if block unreachable.

For the implementation, my initial step involved creating a helper function named good to identify invalid objects.

good = (obj) =>{
    try{return !(invalidIds.includes(obj.sys.id));}
    catch(err){return true;}
}

Now onto the primary traverse function -

traverse = (obj) => {
    //I made the assumption that when an object lacks 'sys' but contains 'id', it must be a sys object.
    if (obj==null) return null;
    if(obj.constructor === Array) return obj.filter(good).map(traverse);
    if(obj.sys==undefined) { //this checks for a sys object.
        if(obj.id!=undefined) return obj;  
    }

    for (let key in obj) {
        if (key!=0) {
            if (good(obj[key])) {obj[key] = traverse(obj[key]);}
            else {obj[key] = null;}
        }
    }
        return obj;
};

With Array objects, following point 2, I filtered out the valid objects initially before mapping them to the traverse function. For Objects, the = operator was used to capture valid sub-objects, returned through a recursive call to traverse, instead of simply altering them.

Important Note: While I have limited knowledge about javascript, I decided to give it a shot due to the common nature of this recursive problem. It's advisable to be cautious of JS-specific issues. Particularly, as mentioned in the comment, I am not entirely satisfied with how I verified 'sys' objects.

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

Issue: EACCES error encountered while attempting to execute bower install operation

After running bower install css-circle-menu, I encountered the following error: /usr/local/lib/node_modules/bower/lib/node_modules/configstore/index.js:54 throw err; ^ Error: EACCES: permission denied, open '/Users/ja ...

Nuxt project encountering issues with loading JS files

I've been integrating a bootstrap template into my Nuxt project but seem to be facing some challenges with loading the necessary scripts. I've attempted to import the scripts into my nuxt.config.js file in a couple of ways: 1.) Initially, I tri ...

How can I securely access and load JSON data from a different domain?

I need to access JSON data from a different domain. The JSON data format is as follows: [ { "siteName": "JQUERY4U", "domainName": "http://www.jquery4u.com", "description": "#1 jQuery Blog for you ...

Is there a way to retrieve the row and parent width from a Bootstrap and Aurelia application?

Is there a way to determine the exact width of a bootstrap grid row or grid container in pixels using Aurelia? I attempted to find this information on the bootstrap website, but I am still unsure as there are multiple width dimensions such as col-xs, colm ...

Utilizing data attributes instead of IDs for connecting buttons and tabs in Javascript tab navigation

I'm currently exploring a new approach to creating Javascript tabs by utilizing data attributes instead of IDs to connect the tab with its content. Here's the concept in action: When clicking on a <button class="tab" data-tab-trigger="1"> ...

Change a MySQL column to store data in JSON format

Is it possible to convert a MySQL column containing varchar(9000) NULL values to the new JSON data type in MySQL 5.7? The column stores valid JSON strings, although some values are null. My attempt to alter the table using the following query: alter table ...

Unable to retrieve information from the wiki API

Here is the link to my codepen project: https://codepen.io/mlestina/pen/OZpOQW?editors=1111 I am having trouble retrieving data from the Wiki API. When I check the Contr-Shift-J readout, I see: Loading failed for the <script> with source “https: ...

Basic AngularJS application, however I am receiving {{this is supposed to be the information}}

Building an angularjs app I have set up an asp.net mvc4 application and integrated the angularjs package using nuget. The Layout.cshtml file has been updated to look like this: <!DOCTYPE html> <html ng-app="myApp"> <head> <meta ...

Connect multiple tables in JSON format

I'm encountering an issue while trying to display data from a JSON file. When I attempt to show the data in a single table, everything works fine. However, if I try to join multiple tables, no data is displayed. <?php mysql_connect($hostname,$user ...

Issues with the styling of C3.js

I'm encountering some issues with a visualization I'm trying to create using C3.js. The top and side edges of my scatter chart are getting cropped (likely due to changing the radius of the bubbles), but I don't believe that should be cau ...

Utilizing Page Methods

I have encountered an issue while using an ajax callback for a void method. When I try to call another method within the calling method, I get an error. Any assistance with resolving this problem would be greatly appreciated. Here is the code snippet: ...

Can a function be embedded within a React render method that includes a conditional statement to update the state using setState()?

My application randomly selects three values from an array found within defaultProps and then displays these values inside div elements in the return JSX. It also assigns these values to properties in the state object. I am facing a challenge where I need ...

Navigating Express HTTP Requests within Apollo Link Context in a NextJS Web Application

Currently, I am in the process of developing a NextJS application and facing a challenge with accessing a cookie to utilize it for setting a Http Header within a GraphQL Request. For this task, I am integrating apollo-link-context. Below is the snippet of ...

Creating Projects Without a Build System in Sublime Text 3

I'm having trouble getting the sublime build system to function properly. When attempting to run my code, I receive a "No Build System" error message. I have already set the build system to Automatic under Tools->Build Systems and saved the file a ...

Error in Flutter: Unhandled Exception. The specific type is '_InternalLinkedHashMap<String, dynamic> JSON request'

I am just starting out with Flutter and I'm experiencing an issue in my app while trying to extract values from JSON data. The problem seems to arise from my HTTP request when I invoke the GetCommands() function and I'm unsure of how to resolve ...

Displaying the specified item within an array using AngularJS

My application features a group of 'players' each with their own unique attributes that I want to showcase within a modal window and cycle through. The user interface is structured like this: <!-- Score Round Modal --> <div class="mo ...

Use JavaScript to sift through an array and exclusively retrieve items that match a specific value

I am working with an array of objects that contain a phase key, and I want to filter out only the ones that have a specific phase value. Additionally, I need to map some other key/value pairs into the final return. Here is my current code: phaseToBlocks ( ...

Issue with JSViews visible link and converter not functioning properly

After updating to the latest version of JsViews, I encountered a problem. When using a data-link like "visible{:property}", everything works fine. However, when using a data-link like "visible{convert:property}", it does not work as expected. It appears ...

The JQuery ajax success callback seems to stick around forever, never getting cleaned up

Apologies for the unusual JavaScript code, as it is compiled from CoffeeScript. Whenever specific events occur in my WebApp, I trigger a callback function to initiate a JSON request: GmScreen.prototype.requestPcUpdate = function(id) { var currentU ...

Executing multiple HTTP requests simultaneously in groups using an asynchronous for loop for each individual request

I'm currently working on running multiple requests simultaneously in batches to an API using an array of keywords. Read Denis Fatkhudinov's article for more insights. The issue I'm facing involves rerunning the request for each keyword with ...