Tips on transforming a list of objects containing arrays of elements into an array of objects with those sub-elements as properties

Background

  • Working on a Node.js project utilizing Mongoose and Pug as the templating engine

Sample JSON data retrieved via Mongoose

[
    {
        "name": "user1",
        "blogs": [
            {
                "title": "blog1",
                "created": "01-01-2020"
            },
            {
                "title": "blog2",
                "created": "01-01-2020"
            }
        ]
    },
    {
        "name": "user2",
        "blogs": [
            {
                "title": "blog3",
                "created": "01-01-2020"
            },
            {
                "title": "blog4",
                "created": "01-01-2020"
            }
        ]
    }
]

Issue

The goal is to display a list of blog posts sorted by creation date while showing the respective user who created each post.

When trying to render the object in Pug using a foreach loop, the data gets grouped by user making it difficult to sort based on creation dates across all blog entries.

Solution involves restructuring the object as follows:

Transformed JSON data mapping each blog post to its user

[
    {
        "name": "user1",
        "blog": {
            "title": "blog1",
            "created": "01-01-2020"
        }
    },
    {
        "name": "user1",
        "blog": {
            "title": "blog2",
            "created": "01-01-2020"
        }
    },
    {
        "name": "user2",
        "blog": {
            "title": "blog3",
            "created": "01-01-2020"
        }
    },
    {
        "name": "user2",
        "blog": {
            "title": "blog4",
            "created": "01-01-2020"
        }
    }
]

This revised data structure allows for displaying user details alongside each blog post and enables sorting by performance creation date.

The challenge lies in achieving this without excessive looping or mapping techniques.

Note

To address this issue, establishing a relationship and resolving keys would be straightforward. The focus here, however, is exploring solutions within a NoSQL context.

How would you approach this scenario and what term best describes this specific operation?

Answer №1

Instead of pulling data from the database in a undesired format and then converting it to the desired format, you can utilize aggregation to directly retrieve the data from MongoDB in the preferred format:

db.collection.aggregate([
  { $unwind: "$blogs" },
  {
    $project: {
      "_id": 0,
      name: 1,
      blogs: 1,
      date: {
        $dateFromString: {
          dateString: "$blogs.created"
        }
      }
    }
  },
  { $sort: { date: -1 } },
  { $project: { date: 0 } }
])

Explanation of the stages used in the above query:

  1. $unwind - Breaks down the blogs array into individual documents with each object in the array

  2. $project - Omits the _id field, reveals the name and blogs fields, creates a new field called date with the value converted from the created field to a date.

  3. $sort - Arranges the documents based on the date field in descending order (from most recent to oldest date)

  4. $project - Conceals the date field in the output documents

For more information on the mentioned aggregation stages, refer to:

Demo:

View this demo to see the query in action.

Answer №2

One approach is to use Array.prototype.reduce. Here's an example that demonstrates this:

const data = [
    {
        "name": "user1",
        "blogs": [
            {
                "title": "blog1",
                "created": "01-01-2020"
            },
            {
                "title": "blog2",
                "created": "01-01-2020"
            }
        ]
    },
    {
        "name": "user2",
        "blogs": [
            {
                "title": "blog3",
                "created": "01-01-2020"
            },
            {
                "title": "blog4",
                "created": "01-01-2020"
            }
        ]
    }
];

const result = data.reduce((acc, curr) => {
    const { name, blogs } = curr;
    const blogArr = blogs.map((blog) => {
        return {
            name,
            blog
        };
    });

    Array.prototype.push.apply(acc, blogArr);
    return acc;
}, []);

console.log(result);

Answer №3

One effective method I would employ is utilizing MongoDB's aggregation feature. The beauty of aggregation lies in its ability to allow you to format your data as desired before retrieving it.

The process of aggregation operates in a sequential manner, with a series of commands executed in the specified order.

In this scenario, the aggregation pipeline would take on the following structure:

[{
    $unwind: {
        path: '$blogs'
    }
}, {
    $project: {
        _id: 0,
        name: 1,
        blog: '$blogs'
    }
}, {
    $sort: {
        "blogs.created": -1
    }
}]

The commands utilized within this pipeline include:

$unwind - This command disassembles an array of items into separate documents, each maintaining the original fields except for the unwound field containing all deconstructed objects.

$project - It offers flexibility in data formatting by allowing field removal, addition, and renaming.

$sort - As implied, this command facilitates document sorting based on specified fields and ordering (ascending or descending).

To delve deeper into aggregation, refer to MongoDB's official documentation:

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

Ways to verify that express middleware triggers an error when calling next(error)

I attempted to capture the error by using next() when stubbing it, but unfortunately it did not work. Below is the function: async getUser (req, res, next) { try { if (!req.user) { throw new CustomError('User not found', 404) } ...

Is it true that DOM objects in JavaScript are considered objects?

I've been searching for an official answer to this question, but it seems there is some confusion. Some people consider DOM objects to be JS objects, while others argue that they are different entities. What is the correct answer? If you search on Sta ...

Utilizing Vue.js with Firestore: Retrieve information from Firestore without rendering any data on the screen

When attempting to display my data from Firestore, I encountered an issue where the data was retrieved successfully when hovering over the <td> tag but not actually displayed. Here is my file for fetching data from Firestore: <template> & ...

Transfer your mongodb database to a Google Cloud Compute Cluster for enhanced performance and scalability

Currently, I have a MongoDB set up in a replica set environment that is hosted with a cloud service provider known as compose.io. Recently, I decided to create a new MongoDB cluster on Google Cloud Compute following these specific instructions. My main go ...

Having trouble retrieving the desired data from the JSON file

My current code is not giving me the expected results while trying to access JSON values with jQuery. Any suggestions on how I can resolve this issue? // JSON response: [{ "private": "8044553.0" }, { "governmentdocs": "98952.0" }, { "officiald ...

ACE.js enhances website security through Content Security Policy

I've been working on setting up a helmet-csp with ace running smoothly. Here's how my helmet-setup looks: var csp = require("helmet-csp"); app.use(csp({ directives: { defaultSrc: ["'self'", "https://localhost:8000"], ...

What is causing my switch statement to not align with any cases?

Whenever I implement a switch statement, none of the cases seem to match the 'prefix' value. However, when I switch to using an if-else statement instead, everything functions correctly. What could be causing this discrepancy? Thanks in advance ...

Organize an array of objects with underscore.js to arrange them in a

I have an array of objects that looks like this: profData=[{"Details":{"CODE":"PAT4PAS","DESCRIPTION":"PASTIE 4N20 12 X 175G","LOCATION":"FREEZER","UNITS":"BOX","WAREHOUSE":"00","AVAILABLE":"15.0000","ON_HAND":"15.0000","BRAND":"4N20","PRICE1":"18.80"," ...

Navigate to a fresh web page without encountering any script loading issues

I am currently working on a web application that loads new pages without requiring the browser to reload. While some pages load perfectly fine, others are causing errors due to missing scripts. The code snippet below is used to load a new page: function lo ...

JavaScript: handle null values along nested object keys by providing a default value

I am dealing with a complex JSON structure that requires pulling out specific information like this let result = data["a"]["b"][0]["c"]["d"][0]["e"][0] What is a streamlined approach to extract the data? A ...

Transform the date into the specified ISO format of YYYY-MM-DDThh:mm:ss.sTZD

I am looking to transform a date into the ISO format YYYY-MM-DDThh:mm:ss.sTZD using JavaScript. Currently, I am able to convert the current date string into the format yyyy-MM-dd'T'HH:mm:ss.SSSZ. For example: 2016-01-11T02:40:33.117Z. However, I ...

Issues with JQuery Ajax file upload functionality in the client's browser causing upload problems

Seeking to integrate a profile picture upload feature with Ajax and JQuery I've been successful in uploading profile pictures to my database on various machines and mobile devices, including Chrome, Edge, Firefox, Safari, and Vivaldi. However, my cl ...

Guide on activating javascript code for form validation using php

How can I activate JavaScript code for form validation? I am currently implementing form validation on a combined login/register form where the login form is initially displayed and the register form becomes visible when a user clicks a button, triggering ...

Utilizing the capabilities of the min.us API

Currently, I am attempting to integrate min.us galleries into a project I am working on, however, I am running into difficulty with accessing their API. As an illustration, here is a JSON snippet taken randomly from a gallery found on google: {"READ_ON ...

What is causing my JavaScript not to load properly within Bootstrap tabs?

I am facing an issue with my website which has Bootstrap 4 tabs implemented in a blade template. The problem arises when there are tabs within tabs, and upon clicking one tab, the slicks Javascript plugin that I created does not load on other tabs. It on ...

Unable to abort AWS Amplify's REST (POST) request in a React application

Here is a code snippet that creates a POST request using the aws amplify api. I've stored the API.post promise in a variable called promiseToCancel, and when the cancel button is clicked, the cancelRequest() function is called. The promiseToCancel va ...

If the display style value matches in JavaScript/jQuery

Is there a way to check if the display is equal to none or to table-row? Here's the code I'm using: Javascript/JQuery: function toggleDisplay(element){ var clickedElement = $(element).closest("li"); var pageList = $(".pagination li"); ...

Separate individual digits from a number and assign them to an array

Looking to store all the individual digits of a number in an array? For example, taking 2017 and creating a vector V = [2, 0, 1, 7]. Here's the code snippet: import array n = 2017 sizeN = 4 m = n i = 1 V = [] while m!=0: ...

Exploring the potential of nested arrays within checkbox inputs

I'm struggling with extracting a nested array from an input value of a checkbox. How should I handle this situation? Here are the values: const othersOptions = [ {procedure:'ORAL PROPHYLAXIS',price: 1000}, {procedure:'TOOTH RESTORATION ...

JavaScript code must be tailored to reference a JS file based on the specific environment, whether it be Production, Development, or staging

I need to determine which .js file to refer based on the URL of Prod, Dev, and QA environments. For Production URLs (domain.com and www.domain.com), I should refer to prod.js file. For Dev and QA URLs (dev.domain.com and staging.com), I should refer to s ...