Tips for simplifying a nested object array to access non-essential content values

I need to extract all unique refIds from a nested object array, regardless of the level they are located at.

Attempting to loop through with for-loops has proven to be overly complex, especially since I'm unsure of the exact depth of the data. However, there is always a

"type": "text"
element with an optional "marks" field.

[
  {
    "type": "bulletList",
    "content": [
      {
        "type": "listItem",
        "content": [
          {
            "type": "paragraph",
            "content": [
              {
                "type": "text",
                "marks": [ // optional mark
                  { "type": "refId", "attrs": { "refIds": [123, 234] } } // need this values
                ],
                "text": "Item 1"
              }
            ]
          }
        ]
      },
      {
        "type": "listItem",
        "content": [
          {
            "type": "paragraph",
            "content": [
              {
                "type": "text",
                "marks": [{ "type": "refId", "attrs": { "refIds": [987] } }],
                "text": "Item 2"
              }
            ]
          }
        ]
      },
      {
        "type": "listItem",
        "content": [
          {
            "type": "paragraph",
            "content": [{ "type": "text", "text": "Item 3" }] // has no mark
          },
          {
            "type": "bulletList", // example for nested child
            "content": [
              {
                "type": "listItem",
                "content": [
                  {
                    "type": "paragraph",
                    "content": [
                      {
                        "type": "text",
                        "marks": [
                          { "type": "refId", "attrs": { "refIds": [876] } }
                        ],
                        "text": "Sub 1"
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

The desired output should be:

["123", "234", "876", "987"]

Answer №1

To gather unique IDs from arrays and objects, simply walk through recursively and store the IDs in a set:

const walk = (arr, out = new Set) => {
  if(Array.isArray(arr)){
    arr.forEach(r => walk(r, out));
  }else if(arr && typeof arr ==='object'){
    for(const key in arr){
      if(key === 'refIds' && Array.isArray(arr[key])){
        arr[key].forEach(r => out.add(r));
      }else walk(arr[key], out);
    }
  }
  return out;

}

const result = [...walk(arr)];

console.log(result);
<script>
const arr=[{type:"bulletList",content:[{type:"listItem",content:[{type:"paragraph",content:[{type:"text",marks:[{type:"refId",attrs:{refIds:[123,234]}}],text:"Item 1"}]}]},{type:"listItem",content:[{type:"paragraph",content:[{type:"text",marks:[{type:"refId",attrs:{refIds:[987]}}],text:"Item 2"}]}]},{type:"listItem",content:[{type:"paragraph",content:[{type:"text",text:"Item 3"}]},{type:"bulletList",content:[{type:"listItem",content:[{type:"paragraph",content:[{type:"text",marks:[{type:"refId",attrs:{refIds:[876]}}],text:"Sub 1"}]}]}]}]}]}];
</script>

Answer №2

It appears that the missing number 876 in the output was a mistake. To address this, you can utilize the .flatMap() method on your array. By mapping each object and checking if its type is text, you can then examine a nested marks array to extract an array of ids using another flatMap. The inner arrays generated by this process will be flattened into the final array returned by the parent .flatMap(), avoiding any nesting issues.

If an object's type is not text, you can recursively call the function getRefIds() with the current object's content to retrieve the refIds from that nested array. This recursive step handles cases where the content may not exist or needs to be ignored when flattening the resulting array. Finally, converting the result into a Set and back into an array helps in deduplicating the values:

// JavaScript code snippet
// Your array data here...

const getRefIds = (arr) => {
  return arr.flatMap(({type, content = [], marks = []}) => type === "text" 
    ? marks.flatMap(mark => mark.attrs.refIds)
    : getRefIds(content)
  );
}

const res = Array.from(new Set(getRefIds(arr)));
console.log(res);

In scenarios where handling large datasets efficiently is crucial, you may opt for a nested recursive approach instead of creating intermediate arrays during each recursive call. The following example illustrates this method to improve performance:

// JavaScript code snippet
// Your array data here...

const getRefIds = (arr) => {
  const refIds = new Set();
  const searchContent = (contentArr) => {
    for(const {type, content = [], marks = []} of contentArr) {
      if (type === "text")
        marks.forEach(mark => {
          if (mark.type === "refId")
            mark.attrs.refIds.forEach(id => refIds.add(id));
        });
      else
        searchContent(content);
    }
  } 
  searchContent(arr);
  return Array.from(refIds);
}

const res = getRefIds(arr);
console.log(res);

Answer №3

function extractAllIDs(content) {
const uniqueIds = new Set();

function searchElements(element) {
    if (element.type === "text" && element.marks) {
        element.marks.forEach(mark => {
            if (mark.type === "refId" && mark.attrs && mark.attrs.refIds) {
                mark.attrs.refIds.forEach(refId => uniqueIds.add(refId));
            }
        });
    }

    if (element.content) {
        element.content.forEach(child => searchElements(child));
    }
}

content.forEach(item => searchElements(item));
return [...uniqueIds];

}

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

Exploring a Ruby nested data structure: accessing a hash within an array nested within another hash, and incorporating a

Hello everyone, I'm diving into Ruby and exploring the world of hashes. After searching for answers here, it seems my question hasn't been fully addressed yet. Currently, I am working with a hash structure that feeds data into a script updating ...

Filtering JSON objects in Vue when the API is only returning a limited number of items

Currently, I am retrieving a JSON Object from an API with a limit of 200. The process involves fetching the initial 200 like this: https://testapi.com/posts.json In our application, we have implemented pagination with 10 posts per page. When we reach pag ...

Accessing an element in an array within the .data section could result in a memory fault due to an address significantly exceeding

My task involves modifying the values within an array using MASM, specifically swapping pairs. array[0] = array[1] array[1] = array[0] array[2] = array[3] array[3] = array[2] and so forth.... I have decided not to utilize the var1 and var2 variables as t ...

Creating a GET endpoint for a RESTful API with nodeJS

Imagine a RESTful web service where various users can share their own articles. When setting up the GET function on the server-side, it would make sense to have async functions like list, getTopViewed, getTopFavorite, and so on. So, is the following code ...

Updating field based on dropdown value in CakePHP 3.6.11

I have the following tables: customers[id, name, surname, phone, text, balance, created] service_types[id, title, price, length, is_subscription, created] customer_service_types[id, customer_id, service_type_id, price, created] Within the add.ctp file o ...

What is the best way to apply a class to a container when a component in AngularJS receives focus or is clicked?

I am trying to apply a class to the container when either the input field is focused or when the dropdown component receives focus or is clicked. The class should be removed when the focus is lost. The requirement is for the input container to have the &a ...

Creating a stunning full-screen background effect using HTML and CSS with the help

I'm currently designing a website with a full-screen background image. To ensure compatibility on all screen sizes, I've incorporated the jQuery Backstretch plugin. However, I've encountered an issue where the text embedded in the backgroun ...

The router should display a component based on the user's access level, even if they are

I'm working on a scenario where the home route needs to cater to both admin and user roles. Is there a way to dynamically display the UserComponent if logged in as a user, and show the AdminComponent if logged in as an admin? This is my current setup ...

When the react autocomplete dropdown appears, it pushes other input elements downward, affecting their

Having implemented an autocomplete dropdown feature by following this link, I am encountering an issue with displaying the dropdown items. As shown in the reference link, the dropdown items are rendered within a div tag with the position set to relative. ...

Condensing a function to tally the distinct characters within a two-dimensional array

I wrote a function to determine the number of unique characters in a 2D array by incrementing a count in a 1D array each time a valid character is found. Then, I check if the count exceeds the height or width of the structure and return false if it does. ...

Combining React, Typescript, and asynchronous Promises

Currently I am in the process of developing a component that interacts with a webservice to fetch data asynchronously using promises. Once the promise is fulfilled, I intend to integrate the results into my component's rendering method. My ultimate go ...

Sequelize error: An unknown column is encountered in the field list while including a model without specifying the `attributes` field

Utilizing Sequelize for executing MySQL queries in my codebase, I have meticulously defined Models and connected them with their associations. Creating a music playlist structure with: Artists who can have multiple songs. Playlists that contain multiple ...

Ways to customize background color for a particular date?

I have been using the fullcalendar npm package to display a calendar on my website. I am trying to figure out how to set a background color for a specific selected date. I tried looking into this issue on GitHub at this link. However, it seems that dayRe ...

Extract and loop through JSON data containing various headers

Having no issues iterating through a simple JSON loop, however, the API I am currently utilizing returns a response with multiple headers. Despite my efforts in various methods to access the results objects, I still face some challenges. The response struc ...

Is it feasible to conceal a certain field once the user has chosen another field?

Looking to create an IF statement that will help me establish a specific rule. On a customer portal page, customers can open tickets via a form where they provide information such as "software product" and "environment" from dropdown lists, as well as othe ...

An error occurred when attempting to use the getDoc() function from Firebase within Next.js: TypeError - reading 'map' on properties of undefined

Hello everyone at StackOverflow, I ran into a problem while attempting to use .map() on a getDoc() constant in my Next.js application. The error message I'm getting is: "TypeError: Cannot read properties of undefined (reading 'map')". As a n ...

Within the ng-repeat loop, every switch button undergoes a status change

Utilizing ng-repeat, I have implemented a feature to display multiple content with on/off buttons. However, when toggling the off button for a specific content, all button states are being changed instead of just the selected one. <div ng-repeat="setti ...

What are the steps for utilizing the Object.entries(...) method along with .forEach and .every

Using a constant queryModifier = {price: "lessThan", weight: "greaterThan"}, I am filtering a list. const queryKeys = keys: { price: '1000', weight: '1000' } const list = [ { // object data here }, { // o ...

Is there a way to use a jQuery puff effect that will automatically bring the Div back to its original state after

I'm currently implementing the jQuery puff effect and I need assistance with bringing the Div back onto the page after it has been puffed away! Right now, the code causes the Div to completely disappear (essentially making it puff away). How can I p ...

What could be causing errors in converting Vue.js code into a single HTML file?

I discovered a Vue.js sample project on this website and now I want to execute this code in a single HTML file using Vue.js. I attempted: <!DOCTYPE html> <html> <head> <title>My first Vue app</tite> <script type="te ...