Transformation of intricate object

I am currently in search of a reliable utility (such as Lodash) that can assist me in transforming deeply nested objects like the example shown below:

Source Data:

  [{
  "category": "blogs",
  "results": {
      "__type": "SearchProvider.SearchResultContainer",
      "SearchResults": [{
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "10/08/2012 6:28:00 AM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408793452500,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }, {
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "03/01/2011 8:16:00 PM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408284893200,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }]
  }
}]

The desired output is to extract the property names id and PublishDate, along with their corresponding values from the MetaData array within each SearchResults object:

Expected Data:

[
    {
        "id": "618",
        "PublishDate": "10/08/2012 6:28:00 AM"
    },
    {
        "id": "605",
        "PublishDate": "03/01/2011 8:16:00 PM"
    }
]

My attempt at using json-query did not yield the desired result. I found the syntax easy to understand, particularly with the help of an online testing tool (), but I was unable to generate the expected outcome.

This question was put on hold for not meeting the guidelines, being labeled as asking for a "recommendation" rather than an explicit solution. While I acknowledge the subjective nature of soliciting recommendations and potentially receiving a varied list of responses, my intention in seeking recommendations was different. I was looking for input from experienced JavaScript developers on various approaches (including those utilizing built-in ES6 features or external utility libraries like Lodash) to objectively achieve this specific outcome. Hence, there is an objective question posed here with an objectively identifiable answer. However, considering the multiple valid methodologies to attain the result, pinpointing a single answer may indeed pose challenges. This issue seems more reflective of a limitation within the Stack Overflow format, leading to the question being considered "off topic." If there exists a platform better suited for posting such inquiries seeking best practices and diverse, constructive responses (like those received thus far), I would gladly redirect my query there. In any case, both responses provided have enriched my understanding about the possible resolutions through different avenues. The response involving ES6 has enlightened me on leveraging its intrinsic capabilities (e.g., destructuring and spread operator) to accomplish the task, while the Lodash approach has shed light on achieving the same goal using that library. I am grateful to both respondents for their valuable insights - ideally, I'd acknowledge both answers for their contributions (though I comprehend why the question deviates from SO guidelines).

Considering my preference for using a "utility" like Lodash, I will opt for the Lodash solution (even though the ES6 explanation furthered my grasp of incorporating its native functionalities).

Answer №1

With Javascript, parsing this structure is a breeze. Utilizing ES6 arrow functions and destructuring only enhances the process:

const data = [{"category":"blogs","results":{"__type":"SearchProvider.SearchResultContainer","SearchResults":[{"SearchId":null,"MetaData":[{"Name":"id","Value":"618","Other":"","Count":0,"Checked":true},{"Name":"PostID","Value":"618","Other":"","Count":0,"Checked":true},{"Name":"PublishDate","Value":"10/08/2012 6:28:00 AM","Other":"","Count":0,"Checked":true},{"Name":"_version_","Value":1571711408793452500,"Other":"","Count":0,"Checked":true}]},{"SearchId":null,"MetaData":[{"Name":"id","Value":"605","Other":"","Count":0,"Checked":true},{"Name":"PostID","Value":"605","Other":"","Count":0,"Checked":true},{"Name":"PublishDate","Value":"03/01/2011 8:16:00 PM","Other":"","Count":0,"Checked":true},{"Name":"_version_","Value":1571711408284893200,"Other":"","Count":0,"Checked":true}]}]}}];

const getValueFromMeta = (meta, name) => (meta.find(({ Name }) => Name === name) || {}).Value; // retrieve value from metadata based on name

/** If the metadata structure remains consistent, you can use this alternative method
const propToIndex = { id: 0, PublishDate: 2 };
const getValueFromMeta = (meta, name) => (meta[propToIndex[name]] || {}).Value;
 **/

const result = [].concat( // combine arrays
  ...data.map(({ results }) => // iterate through data
    results.SearchResults.map(({ MetaData }) => ({ // loop through search results and create object
      id: getValueFromMeta(MetaData, 'id'), // get id value
      PublishDate: getValueFromMeta(MetaData, 'PublishDate') // get publish date value
  })))
);

console.log(result);

Answer №2

By utilizing lodash, you can easily achieve this:

var data = [{
  "category": "blogs",
  "results": {
      "__type": "SearchProvider.SearchResultContainer",
      "SearchResults": [{
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "10/08/2012 6:28:00 AM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408793452500,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }, {
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "03/01/2011 8:16:00 PM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408284893200,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }]
  }
}];

// transformation:
var newData = data[0].results.SearchResults.map(d => {
  return {
    id          : _.find(d.MetaData, {"Name":"id"}).Value,
    PublishDate : _.find(d.MetaData, {"Name":"PublishDate"}).Value
  }
})
    
    
console.log( newData )
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Utilizing ES2015's find method:

var data = [{
  "category": "blogs",
  "results": {
      "__type": "SearchProvider.SearchResultContainer",
      "SearchResults": [{
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "10/08/2012 6:28:00 AM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408793452500,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }, {
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "03/01/2011 8:16:00 PM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408284893200,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }]
  }
}];


var newData = data[0].results.SearchResults.map(d => {
  return {
    id          : d.MetaData.find(item => item.Name == 'id').Value,
    PublishDate : d.MetaData.find(item => item.Name == 'PublishDate').Value
  }
}) 

console.log(newData)

Safeguarding against potential missing keys

If, for instance, there is no match for the find method, it will return undefined. Since undefined is not an object, it does not have a .value key:

Solution:

var newData = data[0].results.SearchResults.map(d => {
  return {
    id : (d.MetaData.find(item => item.Name == 'XXX')||{}).Value, // No match for "find" (undefined)
    PublishDate : (d.MetaData.find(item => item.Name == 'PublishDate')||{}).Value
  }
}) 

This is because:

var a = [{foo:1}];

console.log( a.find(v => v).foo )        // = 1
console.log( (a.find(v => !v)||{}).foo ) // = undefined
console.log( a.find(v => !v).foo )       // ERROR

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

Learn how to access keys and values within a JSON object by utilizing Json.Net in C# programming

Greetings! I am facing a situation where I have a JSON data structure like the one below: { "Id": " 357342524563456678", "title": "Person", "language": "eng", "questionAnswer": [ { "4534538254745646.1": { ...

Converting a JSON array to C# and vice versa in Xamarin Forms

I've been struggling to send a C# object as JSON array to an API endpoint. I feel like I'm going crazy trying to solve these issues. Here's a sample of the JSON data: Array ( [user_id] => 0002323445635 [order] => {"order":{" ...

Disabling collapse in Bootstrap 5 is impossible using stopPropagation() when clicking on a particular element

I'm attempting to prevent an element from collapsing/expanding when clicking a checkbox inside it. In my example on codepen, my code worked fine with Bootstrap v4, but after switching to v5, the stopPropagation function doesn't seem to work. Yo ...

Switch from using fetch to utilizing axios for making API requests

I used fetch for a 'get' request, but now I want to switch to axios. Can someone please help me convert this code to use axios instead? More details: I am fetching an image and using the blob method to display it to the user. I would like to ach ...

Strategies for accessing the initial portion of an AJAX response

When using ajax to call an URL with dataType HTML, the response includes two parts such as accesstoken=1&expires=452. In this scenario, only the access token is needed. Using alert(response) displays both parts. How can the access token be extracted? ...

What exactly is the significance of the </< in THREE.Camera.prototype.lookAt</<()?

After experimenting with THREE.js for a while, I came across something peculiar: When using Firefox and opening the developer console to type camera.lookAt (assuming your camera is named camera), it displays function THREE.Camera.prototype.lookAt</< ...

Guide on showing a message on the server side when pressing a button in the web browser

I need the following question to function seamlessly on all major browsers including Opera, Internet Explorer, Chrome, Safari, and Firefox I am working on an application that requires users to follow a specific order of pages Text1.php, Text2.php, Text3.p ...

Passport - Pairing Plan "Error|The username provided for sign_request() is not recognized"

Currently experimenting with duo in node.js using passport to test its implementation in an application....Utilizing a passport-duo strategy and encountering issues when trying to apply the example provided in my own project. The GitHub repository for pass ...

Transform various tables enclosed in separate div elements into sortable and filterable tables

I'm encountering an issue with making multiple tables sortable and searchable on one page. Despite all the tables having the same class and ID, only the first table is responsive to sorting and searching. I've followed a tutorial that recommends ...

Adjust the font size based on the dimensions of the container

I'm currently working on a script that dynamically sets the font-size based on the container's dimensions and the length of the text. This is what I have implemented so far. window.onload = function () { var defaultDimensions = 300; ...

Toggle checkbox feature in Bootstrap not functioning properly when placed within ng-view

When attempting to embed a bootstrap toggle checkbox within <ng-view></ng-view>, an issue arises where a regular HTML checkbox is displayed instead of the expected bootstrap toggle. Strangely, the same checkbox functions as a bootstrap toggle w ...

How can I retrieve the latest state of the Redux store in getServerSideProps in Next.js?

I am attempting to retrieve the most up-to-date redux state in getServerSideProps like so: export const getServerSideProps = async (ctx) => { const state = store.getState(); console.log(state.name); return { props: { login: false } }; }; H ...

Check to see if two sets of coordinates fall within the specified radius

I'm currently working on analyzing the collision data for major intersections in my city by aggregating it with the location information. My main goal is to determine the number of accidents that occurred within a 20-meter radius of each intersection. ...

Inaccurate Guild Member Filtering

Recently, I've been working on creating a unique member counter for my server. The goal is to accurately count the total number of members in the server, excluding bots, and counting only bots as well. However, when I attempt to display these counts i ...

Unfulfilled expectation of a promise within an array slipping through the cracks of a for loop

I have a function that generates a Promise. Afterward, I have another function that constructs an array of these promises for future utilization. It is important to note that I do not want to execute the promises within the array building function since so ...

The error message thrown: "Failed to convert to JSON data type"

I have a code snippet below regarding the main_menu.java file. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_menu); getData(); } pr ...

How can I initiate an AJAX POST request over HTTPS?

Despite my efforts, I am consistently encountering a 404 error when attempting to make an Ajax POST request. The specific error message reads: "GET 404 (Not Found)." Could this issue be related to the site's use of https? Below is the code snippet t ...

Is there a way to manipulate a button's toggle state using Javascript as the page loads?

I am in the process of developing a straightforward web application that allows users to customize their settings. On the settings page, there are several toggle buttons that need to have their state changed during the page load to align with the preferenc ...

AngularJS: Issue with watching arrays and deep $watch functionality

I'm having trouble using the $watch function in AngularJS with an array of boolean values. I want to display a message when there's a change in the array, but it's not working as expected. Check out this code example where the array values ...

Top spot for placing a file containing a polyfill to ensure cross-browser compatibility in JavaScript projects

Curious about the best location within a React / Redux app (built with create-react-app) to store custom polyfill files for browsers that do not support certain features. I specifically require Array.prototype.includes and String.prototype.startsWith, as ...