What is the best method for organizing an array of objects based on their subobjects?

When developing a web app's back-end with TypeScript, I've found intersection types to be incredibly beneficial for optimizing SQL queries. Imagine having the following tables:

User

userId: number
userEmail: string

Post

postId: number
userId: number (FK)
postBody: string

By combining these two tables into an intersection type (User & Post), we get:

{
  userId: number;
  userEmail: string;
  postId: number;
  postBody: string;
}

This allows us to represent rows returned from a joined select query using this type.

The challenge arises when we need to deconstruct this data on the web server. Writing iterative code to group results for every query can become repetitive. The desired transformation is as follows:

Input:

[
  {
    userId: 1,
    userEmail: 'user1@example.com',
    postId: 1,
    postBody: 'User 1\'s first post',
  },
  {
    userId: 1,
    userEmail: 'user1@example.com',
    postId: 2,
    postBody: 'User 1\'s second post',
  },
  {
    userId: 2,
    userEmail: 'user2@example.com',
    postId: 3,
    postBody: 'User 2\'s first post',
  },
]

Output:

[
  {
    userId: 1,
    userEmail: 'user1@example.com',
    posts: [
      {
        postId: 1,
        postBody: 'User 1\'s first post',
      },
      {
        postId: 2,
        postBody: 'User 1\'s second post',
      }
    ],
  },
  {
    userId: 2,
    userEmail: 'user2@example.com',
    posts: [
      {
        postId: 3,
        postBody: 'User 2\'s first post',
      }
    ]
  }
]

I'm looking to create a dynamic function for achieving this, by passing in the collection, an array of parent key names, and the name of the child collection. My attempt at implementing this function resulted in:

function group(coll: Array<any>, parentKeys: Array<string>, childCollName: string): Array<any>;

If anyone has suggestions or can assist with the implementation, it would be greatly appreciated.

So far, efforts have been made with Lodash but the groupBy function doesn't handle subobjects equally, leading to unexpected results such as an array of three objects instead of a nested structure.

Answer №1

Why not test out a method similar to the one below, which involves looping and creating objects?

var array = [
    {
        userId: 1,
        userEmail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="02777167703342676f636b6e2c616d6f">[email protected]</a>',
        postId: 1,
        postBody: 'User 1\'s first post',
    },
    {
        userId: 1,
        userEmail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ea9f998f98dbaa8f878b8386c4898587">[email protected]</a>',
        postId: 2,
        postBody: 'User 1\'s second post',
    },
    {
        userId: 2,
        userEmail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f085839582c2b0959d91999cde939f9d">[email protected]</a>',
        postId: 3,
        postBody: 'User 2\'s first post',
    },
];

function createPost(object) {
    var post = {};
    post.postId = object.postId;
    post.postBody = object.postBody;
    return post;
}
function convertArray(array) {
    var map = {};
    for (var i = 0; i < array.length; i++) {
        var currentObject = array[i];


        if (!map[currentObject.userId]) {
            var obj = {}
            obj.userId = currentObject.userId;
            obj.userEmail = currentObject.userEmail;
            obj.posts = [];

            map[obj.userId] = obj;

        }
        obj.posts.push(createPost(currentObject));
    }
    var keys = Object.keys(map);
    return keys.map(function (value) { return map[value]; });
}
var result = convertArray(array)
console.log(result);

Answer №2

To accomplish this task, you can utilize the Array.prototype.reduce() method.

var source = [{
        userId: 1,
        userEmail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="42373127307302272f232b2e6c212d2f">[email protected]</a>',
        postId: 1,
        postBody: 'User 1\'s first post',
    },
    {
        userId: 1,
        userEmail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c6b3b5a3b4f786a3aba7afaae8a5a9ab">[email protected]</a>',
        postId: 2,
        postBody: 'User 1\'s second post',
    },
    {
        userId: 2,
        userEmail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="493c3a2c3b7b092c24282025672a2624">[email protected]</a>',
        postId: 3,
        postBody: 'User 2\'s first post',
    },
]

var grouped = source.reduce(function(v, k) {
    if (!v[k.userId]) {
        v[k.userId] = {};
    }
    var group = v[k.userId];
    group.userId = k.userId;
    group.userEmail = k.userEmail;
    if (!group.posts) {
        group.posts = [];
    }
    group.posts.push({
        postId: k.postId,
        postBody: k.postBody
    });
    return v;
}, {})

var dataArray = [];
for (var o in grouped) {
    if (grouped.hasOwnProperty(o)) {
        dataArray.push(grouped[o]);
    }
}

console.log(JSON.stringify(dataArray, null, 2));

Answer №3

Here's a different approach using reduce, some, and the concept of destructuring

DEMO

const allData = [
  {
    id: 1,
    name: 'John Doe',
    age: 25,
  },
  {
    id: 2,
    name: 'Jane Smith',
    age: 30,
  },
  {
    id: 3,
    name: 'Alice Johnson',
    age: 35,
  }
];

const processedData = allData.reduce((acc, item) => {
    const { id, ...rest } = item;
    let index;
    let person;

    const accHasId = acc.some((obj, i) => {
        if (obj && obj.id === id) {
            index = i;
            return true;
        }
        return false;
    });

    if (!accHasId) {
        person = { id, information: [rest] };
        acc.push(person);
    } else {
        acc[index].information.push(rest);
    }

    return acc;
}, []);

console.log(JSON.stringify(processedData));

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

I am attempting to link my Firebase real-time database with Cloud Firestore, but I am encountering import errors in the process

I am currently working on enhancing the online functionality of my chat app by implementing a presence system using Firebase Realtime Database. Here is the code snippet that I have created for this purpose: db refers to Firestore and dbt refers to the Rea ...

Using the result of one function in another function when using async await

I am facing an issue with running a function based on the return value of another function: // in utils.js methods:{ funcOne(){ // do some thing return true } } //in component.vue methods:{ funcTwo(){ let x = this.funcOne() if(x){ ...

Enhancing Your C# Code with Custom Extension Methods

I am currently working on developing a few extension methods that will be applied to various collections, specifically those that implement IList and array collections []. Whenever I create an extension method, I find myself needing to create two versions ...

The information within the ajax request remains static

I made changes to my ajax data, saved it and even double-checked the file location. However, the old version is still appearing as if it's cached. Here is the original code: function setMessages(roomId, username, message){ $.ajax({ type: ...

The AJAX POST request encountered an error

I apologize for the lackluster title. Basically, when the script is executed, it triggers an 'error' alert as shown in the jQuery code below. I suspect that the issue lies in the structure of my JSON data, but I'm uncertain about the necess ...

Unable to retrieve text content from dynamically created element in JavaScript?

I'm currently facing an issue while working on a school project. The problem arises with a textContent error when I attempt to import a JSON file and utilize the data in a foreach loop. Despite defining the properties with elements from the JSON file, ...

Displaying all notifications while using parameters in TypeScript

I am trying to display all of my notifications in HTML. The value is returned in res = response.json();, but my website only shows one notification, similar to the example in https://i.sstatic.net/ECbyx.png Let's start with this code: public event ...

Insert this HTML table along with radio buttons into an Excel spreadsheet

My HTML table contains rows with a variety of content, including plain text characters and elements like radio buttons and lists. I want users to be able to copy-paste the table into MS Excel as plain text and have the radio button values replaced with "c ...

Angular 12 Directive causing NG-SELECT disabled feature to malfunction

Looking for a way to disable ng-select using a directive. Does anyone have any suggestions on how to accomplish this? Here is the code I have been working with, along with an example that I was trying to implement. setTimeout(() => { const selectElem ...

Strip the date after converting from milliseconds to a date

When my server back end sends the time value as milliseconds (1479515722195), I use a library function to convert it to a date format like Sat Nov 19 2016 11:35:22. Now, I need to figure out how to separate the date and time components. I only require th ...

Why does the width of my image appear differently on an iPhone compared to other devices?

I recently encountered an issue with the responsiveness of an image on my website. While it displayed correctly on Android and desktop devices, the image appeared distorted on iPhones as if the CSS width attribute was not applied properly. This problem spe ...

Using TypeScript to create a function with an argument that is optional based on a condition

I need a function that will only take a second argument when certain conditions are met. let func = <T extends boolean>(arg1: T, arg2: T extends true ? void : string) => {}; func(true); // ERROR Expected 2 arguments, but got 1 func(true, undefin ...

Error: Trying to access a property that does not exist (postgresClient) on an undefined variable

For my latest project, I've been working on creating an API that utilizes PostgreSQL to store shortened links. However, I keep encountering the issue where postgreClient is consistently undefined when attempting to run a query to the database. In my ...

Develop a regular expression control specifically designed to validate URLs

I encountered a issue with my current web application. When I access the link: https://localhost:44311/#shop, the page loads perfectly as expected. Here is a screenshot: https://i.sstatic.net/6G6CJ.png However, when I try to change the URL to: https://loc ...

Exploring the world of Node.js, JSON, SQL, and database tables

Hello everyone, I have been working on a project using Node.js and Express framework. My current goal is to create a client-side page that allows users to input form data into a MySQL database. I have managed to successfully insert and retrieve data from ...

Steps to import shared CSS using Styled-components

In my project using react, I've implemented styled-components for styling. One requirement is to have a shared loading background. Here is the code snippet of how I defined it: const loadingAnimation = keyframes` 0% { background-position: 95% 95%; } ...

Issue with jqGrid when filtering small numerical values

Happy Holidays! I recently came across an issue while trying to filter small numbers using jqGrid. I am filtering numbers that can vary from 10 to 1, down to values as small as 10^(-8) or even smaller. The filtering works well for these numbers until they ...

What causes certain event handlers to be activated when using dispatchEvent, while others remain inactive?

When it comes to event-based JS, there are two main APIs to consider: event listeners and event handlers. Event listeners can be registered using addEventListener, while event handlers are typically registered with an API similar to target.onfoobar = (ev) ...

Troubleshooting 404 errors with Cordova, AngularJS, and Node.js (Express) when using $http with

I'm currently testing in an Android environment using Cordova, AngularJS, and Node.js (Express). I'm attempting to retrieve some data using $http(), but consistently encountering a 404 error message (as seen in the alert below). Here's the ...

Passing a PHP variable between PHP files with the help of jQuery

I'm facing a minor issue. I'm trying to pass a PHP variable from one PHP file to another using setInterval. However, I'm unsure of how to include the PHP variable in my jQuery code. Here is the content of first.php: <?php $phpvariable= ...