Having difficulty formulating a MongoDB query that includes a subquery

I have a dataset structured as follows:

{
  "id": "02741544",
  "items": [{
    "item": "A"
  }]
}, {
  "id": "02472691",
  "items": [{
    "item": "A"
  }, {
    "item": "B"
  }, {
    "item": "C"
  }]
}, {

  "id": "01316523",
  "items": [{
    "item": "A"
  }, {
    "item": "B"
  }]
}, {
  "id": "01316526",
  "items": [{
    "item": "A"
  }, {
    "item": "B"
  }]
}, {
  "id": "01316529",
  "items": [{
    "item": "A"
  }, {
    "item": "D"
  }]
},

I am attempting to create a query that generates an output in the following format:

{
  "item": "A",
  "ids": [{
    "id": "02741544"

  }, {
    "id": "02472691"

  }, {
    "id": "01316523"

  }, {
    "id": "01316526"

  }, {
    "id": "01316529"

  }]
}, {
  "item": "B",
  "ids": [{
    "id": "02472691"

  }, {
    "id": "01316523"

  }, {
    "id": "01316526"

  }]
}, {
  "item": "C",
  "ids": [{
    "id": "02472691"

  }]
}, {
  "item": "D",
  "ids": [{
    "id": "02472691"

  }]
},

Essentially, I am aiming to extract unique items from the item array within each object, and then create an array of ids for each object containing that item in its item array.

Answer №1

It is recommended to utilize the aggregation framework, where a series of pipeline steps need to be executed in a specific order:

  1. $unwind - This initial step will flatten the items array, generating a copy of each document per array entry. This is important for downstream processing of documents as denormalized entities that can be grouped together.
  2. $group - This step groups the flattened documents by the item subdocument key and creates the ids list using the $push accumulator operator.

-- UPDATE --

As highlighted by @AminJ in the comments, if items may have duplicate item values and you wish to avoid duplicate ids in the result, consider using $addToSet instead of $push.

An example illustrating this approach is:

db.collection.aggregate([   
    { "$unwind": "$items" },
    {
        "$group": {
            "_id": "$items.item",
            "ids": { 
                "$push": { "id": "$id" } /* or utilize 
                "$addToSet": { "id": "$id" } if duplicate ids should be avoided */                    
            }
        }
    }
])

Sample Output

{
    "_id" : "A",
    "ids" : [ 
        { "id" : "02741544" }, 
        { "id" : "02472691" }, 
        { "id" : "01316523" }, 
        { "id" : "01316526" }, 
        { "id" : "01316529" }
    ]
}

/* 2 */
{
    "_id" : "B",
    "ids" : [ 
        { "id" : "02472691" }, 
        { "id" : "01316523" }, 
        { "id" : "01316526" }
    ]
}

/* 3 */
{
    "_id" : "C",
    "ids" : [ 
        { "id" : "02472691" }
    ]
}

/* 4 */
{
    "_id" : "D",
    "ids" : [ 
        { "id" : "01316529" }
    ]
}

The output of an aggregate() call is a cursor pointing to the documents generated by the final stage of the aggregation pipeline. To obtain the results in an array format, you can use the cursor's toArray() method, which returns an array containing all the documents.

For instance:

var pipeline = [    
        { "$unwind": "$items" },
        {
            "$group": {
                "_id": "$items.item",
                "ids": { 
                    "$push": { "id": "$id" } /* or utilize 
                    "$addToSet": { "id": "$id" } if duplicate ids should be avoided */                   
                }
            }
        }
    ],
    results = db.collection.aggregate(pipeline).toArray();

printjson(results);

Answer №2

One way to tackle this problem is by utilizing an aggregation pipeline method:

db.collection.aggregate([
    {
        $unwind: "$items"
    },
    {
        $project: {
            id: 1,
            item: "$items.item"
        }
    },
    {
        $group: {
            _id: "$item",
            ids: {
                $push: "$id"
            }
        }
    }
])

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

It can be frustrating to have to refresh the page twice in order to see changes when utilizing the revalidate feature in Next

When I make the REST call to fetch data for my page using the code below: // src/app/page.js const Home = async () => { const globalData = await getGlobalData(); return ( <main'> <SomeComponent data={globalData} /> < ...

JavaScript class with callback function commonly used

I am looking to create a JavaScript class that can register multiple functions to run with a common callback. Each registered function should run asynchronously, and once they have all completed, the specified callback function should be executed. In addi ...

Error 400: The onCreate Trigger function for Cloud functions is experiencing issues with HTTP requests due to errors in the request

I am encountering an issue when attempting to add a trigger for Firestore OnCreate, as the deployment fails with HTTP Error: 400 stating that the request has errors. Essentially, my goal is to write to a new document if a record is created in a different ...

The JavaScript for loop using .appendChild() is inserting the values of the final object, represented as [object object], into the HTML document

$(document).ready(function () { GetDetails(); }); function GetDetails() { let albumlist = document.getElementById("album-list"); $.ajax({ url: '/Store/browseajax', type: 'GET', data: { id: '@ ...

Guide on exporting values from a Promise within an imported module

Recently, I encountered a challenge where I needed to integrate a pure ESM package into a non-module. Unfortunately, modifying the script to accommodate this requirement was not an option. To tackle this issue, I turned to using the import() function (als ...

"Enhance your website with the powerful autocompletion feature of

I am using Zend Framework to create a form element that utilizes Zend_Dojo_Form_Element_ComboBox. By setting dojox.data.QueryReadStore as the store type, I am able to generate a list of selectable values in my HTML input field. This allows me to either cho ...

Throttle the RxJs interval based on the inner observables

Sorry if the way I am asking this question is not clear, I am having difficulty finding the right words to explain it. I am currently working on Selenium automation and here is how the process goes:- Go to a specific page Every 1 second, check if the pag ...

Switching the default image using jQuery upon click event

When I click on the image, I want to see a new image appear for just one second before returning to the default. I tried using setTimeout() function, but even after one second, I still see the same pressed.svg image. Here is my complete code: <html> ...

Prevent Float Filtering in AngularJS

As I work on creating a directive in AngularJs, I am facing an issue. The directive is supposed to receive a JSON object from the app controller and display its content accordingly. To better illustrate my problem, I have created a simple demo which can b ...

To combine arrays A and B within a React useState object, simply pass them as arguments when initializing the state

Currently, I am working on integrating infinite scroll functionality in React, where I need to fetch data from a backend API for loading content on the next page. The challenge I'm facing is that my state is set as an object using useState, and I need ...

Database-Driven Ajax Information Display

https://i.sstatic.net/GE8RI.pngI retrieved some data from the database and successfully displayed it after an ajax call. However, one of the variables contains array data that was saved using the implode function. The data looks like (a,b,c,d). The curren ...

Show a variety of pictures in a random arrangement?

Looking for some help here! I'm trying to shuffle my images in a random order each time the page is refreshed. It's like a game of musical chairs but with pictures! Does anyone know how to achieve this? I've done some searching, but haven& ...

Troubleshooting the "@material-ui/core" issue in React: Step-by-step guide

Issue with React: Unable to locate the '@material-ui/core' module in 'C:\Users\user\Downloads\inTech'22-Web Development (EDUGEN)\edu-gen\src\components' Resolution Command: To resolve, run npm in ...

I noticed that my API call is being executed twice within the router function

In my NextJs project, I am utilizing Express for routing. I have implemented a router with a dynamic :id parameter which triggers an axios call to check the ID in the database. However, I am facing an issue where the API is being called twice when the :id ...

Using JavaScript, reload the page once the data has been retrieved from an Excel spreadsheet

I'm facing an issue with my JavaScript code. Here's what I have: a = Excel.Workbooks.open("C:/work/ind12.xls").ActiveSheet.Cells.find("value"); if(a == null) document.getElementById('dateV ...

Retrieve data from a JSON array using either JavaScript or PHP

Check out my code snippet: const newData = [{"new_id":"1","new_no":"1","total":"N.A"},{"new_id":"2","new_no":"3","total":"4"},{"new_id":"2","new_no":"4","total":"5"}]; Now, I need to extract specific details from this JSON data based on the 'new_no& ...

Can someone help me figure out this lengthy React error coming from Material UI?

Issues encountered:X ERROR in ./src/Pages/Crypto_transactions.js 184:35-43 The export 'default' (imported as 'DataGrid') could not be found in '@material-ui/data-grid' (potential exports include: DATA_GRID_PROPTYPES, DEFAULT ...

Techniques for finding the total value of a JSON array

After retrieving values from a database, I am using them in JSON/javascript as an array. For example, see https://i.sstatic.net/nLzk9.png The issue arises when trying to calculate the sum of the array elements. I attempted to solve it with this code: v ...

Tips on making an array readable by JavaScript using Jinja2 and Google App Engine

I'm currently facing an issue with transferring an array from a server to a web page through Jinja2 in Google App Engine. Despite my efforts, I'm struggling to make the array readable by my jQuery code. This is all new to me as it's my first ...

How can the value be accessed when using getElementById in Angular for <mat-select> elements that do not have a value attribute?

Within a loop, I have an element that has a dynamically generated id: <mat-select multiple class="dw-input" [value]="element.txn_type_id ? element.txn_type_id.split(',') : []" id="field-{{element.Name}}-txn_type_id&quo ...