Combining data to form Nested Arrays

I have a dataset of records stored in a database and I've been attempting to extract a complex set of information from these records.

Here are some sample records for reference:

{
    bookId : '135wfkjdbv',
    type : 'a',
    store : 'barnes & noble',
    shelf : 'A1'
}
{
    bookId : '13erjfn',
    type : 'b',
    store : 'barnes & noble',
    shelf : 'A2'
}

I'm looking to extract data that will provide, for each unique bookId, the count of records per shelf for each store where the book belongs to type 'a'.

Although I am aware that an aggregation query allows for various operations such as grouping and matching, I have not yet found a solution to this particular problem.

The desired output should look like this:

{
   bookId : '135wfkjdbv',
   stores : [
       {
           name : 'barnes & noble',
           shelves : [
                {
                     name : 'A1',
                     count : 12
                },
           ]
       },
       {
           name : 'books-a-million',
           shelves : [
                {
                     name : 'B3',
                     count : 8
                },
                {
                     name : 'D5',
                     count : 15
                },
           ]
       }  
   ]
}

Answer №1

Understanding the process is not as challenging as it may seem at first glance. The aggregation "pipeline" operates by passing results from one stage to the next for processing, similar to how a Unix "pipe" functions:

ps -ef | grep mongo | tee out.txt

In this specific example, there are three $group stages involved. The initial stage performs basic aggregation, while the subsequent two stages "roll up" the necessary arrays in the output.

db.collection.aggregate([
    { "$group": {
        "_id": {
            "bookId": "$bookId",
            "store": "$store",
            "shelf": "$shelf"
        },
        "count": { "$sum": 1 }
    }},
    { "$group": {
        "_id": {
            "bookId": "$_id.bookId",
            "store": "$_id.store"
        },
        "shelves": { 
            "$push": {
                "name": "$_id.shelf",
                "count": "$count"
            }
        }
    }},
    { "$group": {
        "_id": "$_id.bookId",
        "stores": {
            "$push": {
                "name": "$_id.store",
                "shelves": "$shelves"
            }
        }
    }}
])

It may be tempting to use $project at the end to rename _id to

bookId</code, but it's important to remember that <code>_id
serves as the primary key. Developing good habits from the start will prevent unnecessary complications and costs associated with such alterations.

The essence of this operation lies in crafting the grouping details into the primary keys of each $group. Each subsequent stage then organizes these groupings into array structures, progressively condensing the grouping fields with their corresponding counts. This concept aligns with the SQL syntax:

GROUP BY bookId, store, shelf

From organizing shelves within stores to aggregating stores within bookIds, the pipeline structure efficiently iterates through data transformations. By visualizing the process as a series of interconnected forms, users can effectively fold results into hierarchical arrays.

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

Why is a <script> tag placed within a <noscript> tag?

Lately, I've been exploring various websites with unique designs and content by inspecting their source code. One site that caught my attention was Squarespace, which had blocks of <script> tags within a <noscript> tag: <!-- Page is at ...

What sets apart using the loadText function from loadText() in JavaScript?

I've implemented a basic JS function that loads text lines into an unordered list. Javascript function loadText() { document.getElementById("text1").innerHTML = "Line 1"; document.getElementById("text2").innerHTML = "Line 2"; document.ge ...

Can transclusion be achieved while maintaining the directive's scope in Angular?

Can we achieve the following functionality in Angular? <div ng-controller="MainCtrl" ng-init="name='World'"> <test name="Matei">Hello {{name}}!</test> // I expect "Hello Matei" <test name="David">Hello {{name}}!&l ...

The functionality does not seem to be functioning in Mozilla Firefox, however it is working correctly in Chrome when the following code is executed: `$('input[data-type="choise"

I am currently working on an online test portal and everything is functioning properly with Chrome. However, I am encountering an issue with Mozilla Firefox. My code works fine in Chrome but not in Mozilla Firefox. Please suggest an alternative solution to ...

Creating a new document or collection by posting an aggregation

Currently, I am working with a client where a form is submitted and stored in a Mongo database. I have performed an aggregation to identify individuals who have selected the same place, date, and time. My goal now is to create a Mongo document that stores ...

Is there a method to programmatically identify enterprise mode in IE11?

Is it possible to detect Internet Explorer 11 Enterprise mode programmatically? This would involve detecting at the server side using C# or JavaScript/jQuery. The discussion on the following thread has not reached a conclusive answer: IE 11 - Is there a ...

What is the process for storing data in Zend Framework 2 using MongoDB with Doctrine 2 ODM?

I created a controller in zf2 to save data in mongodb, but it is not saving any record in the event table. How can I successfully save the data? Here is the code snippet: public function createAction() { $calendar_id = (int) $this->p ...

What is the best way to display a div box only when a user checks a checkbox for the first time out of a group of checkboxes, which could be 7 or more, and then hide the

Is there a way to make a div box appear when the user checks any of the first checkboxes? I have attempted using the following codes: JQ Codes: $('#checkbox').change(function() { if ($(this:first).is(':checked')) { cons ...

Identifying the various types in Typescript

In the process of developing a solution for Excel involving data from an Office API, I encountered the challenge of distinguishing between different types that a function can return. Specifically, the data retrieved as a string may belong to either a "Cell ...

Accessing Nested States in Angular: A How-To Guide

Looking to access a nested state? Here's how it can be done in your routes.js: .state('menu', { url: '/side-menu-ineevent', templateUrl: 'templates/menu.html', abstract:true }) .state('menu.settings.privacy_policy&a ...

Is there a way to call class methods from external code?

I am seeking clarification on Class files. Below is an example of a Class that I have: class CouchController { constructor(couchbase, config) { // You may either pass couchbase and config as params, or import directly into the controller ...

Modify the events JSON URL when the Full Calendar changes its display period

Whenever I switch between months or weeks, I need the JSON URL link to update accordingly. For example: The initial JSON URL is: /json/?start=2018-01-28&end=2018-03-10 When moving to the next month, the URL changes to: /json/?start=2018-02-25&am ...

Require assistance in creating an event that triggers an action when clicked, while another event remains inactive upon clicking

<FullCalendar allDaySlot={true} eventClick={(info) => this.openReservationInfoModal(info.event)} events={[...milestones.map(milestone => ({ id: milestone.id, ...

Setting up redux with Next.js: a step-by-step guide

After setting up redux in this manner, everything is functioning properly. The _app.js file has been reorganized as follows : import App from 'next/app'; import { Provider } from 'react-redux'; import withRedux from 'next-redux-wr ...

Animating jQuery to adjust height based on a percentage

My animation using percentage is not working as expected. It expands to the whole height instantly instead of smoothly transitioning to 100%. Here is my CSS code: #block-views{ overflow:hidden; height:20px; } This is my HTML code: <div id="block-view ...

Capture the responseBody data within a Newman script from a Postman collection and save it to a

I'm trying to execute a script.js using newman with a locally saved postman collection. The call is successful in postman, returning a token in the response body that I need to access. I would prefer not to open postman every time just to get the res ...

Is there a method to establish a connection between two models in a MERN stack application and retrieve the user ID from the other

Encountering an error when attempting to add a new note to MongoDB Atlas involving two models, notes and User. The error indicates that the user is not recognized or has an undefined id. Seeking guidance on how to resolve the error and successfully add a s ...

Discover all undefined variables in the project using Node.js

Currently working on developing a backend API using Node.js Encountering issues at times where unit tests fail and error message 'data is not defined' appears Fortunately, TypeScript has proven beneficial in resolving such problems with its l ...

Encountering a Bad Request error while attempting to refresh the Django login access token

Attempting to refresh the access token received from Django every few seconds, however encountering an error message Request Method: POST Status Code: 400 Bad Request Sending the refresh token to this endpoint: "http://127.0.0.1:8000/api/token/refre ...

Transferring data obtained from an API in node.js to display in an HTML table

I'm currently diving into node.js and development of a web application aimed at managing stock market portfolios for investors. One challenge I'm facing is figuring out how to transfer the data collected from an API to a specific table cell in HT ...