calculate the count field dynamically based on $bucket boundaries in a MongoDB aggregate operation

I'm currently utilizing the Mongo aggregate framework and have a collection structured like this:

[
  {
    _id: 123,
    name: "john",
    age: 30,
    fruit: "apple",
    
  },
  {
    _id: 345,
    name: "moore",
    age: 45,
    fruit: "mango",
    
  },
  {
    _id: 545,
    name: "carl",
    age: 30,
    fruit: "grape",
    
  },
  {
    _id: 96,
    name: "shelby",
    age: 25,
    fruit: "apple",
    
  },
  {
    _id: 86,
    name: "loris",
    age: 48,
    fruit: "mango",
    
  },
  {
    _id: 76,
    name: "carl",
    age: 55,
    fruit: "grape"
  }
]

My goal is to query and create a pipeline that returns the count of specific fruits falling under certain $bucket boundaries. The desired result should look like this...

[
  {
    "_id": Specific_Boundary,
    "userCount": Number_Of_Users_Falling_Under,
    "fruitsLie": [
                    {fruit_names_of_users_in_this_boundary : fruit_counts},
                  ]
  },
  {
    "_id": 0,
    "userCount": 3,
    "fruitsLie": [
                    {apple: 2},
                    {grape: 1}
                  ]
  },
  {
    "_id": 40,
    "userCount": 2,
    "fruitsLie": [
                    {mango: 2}
                 ]
  },
  {
    "_id": "more than 50",
    "userCount": 1,
    "fruitsLie": [
                    {grape: 1}
                 ]
  }
]

For example, under the age of 30 we have 3 users - 2 eat apples and 1 eats grapes, so the fruitsLie field performs these calculations.

What are the various approaches available to solve this problem with specific $bucket boundaries? Please provide a detailed explanation for each stage as I am new to aggregates and still learning...

Answer №1

Here is a method to achieve the desired outcome:

db.collection.aggregate([
  {
    "$bucket": {
      "groupBy": "$age",
      "boundaries": [
        0,
        31,
        41,
        51,
        
      ],
      "default": "More than 50",
      "output": {
        "users": {
          $push: "$$ROOT"
        }
      }
    }
  },
  {
    "$unwind": "$users"
  },
  {
    "$group": {
      "_id": {
        _id: "$_id",
        fruit: "$users.fruit"
      },
      "count": {
        "$sum": 1
      },
      
    }
  },
  {
    "$group": {
      "_id": "$_id._id",
      "fruitsLie": {
        "$push": {
          "$concatArrays": [
            [],
            [
              [
                "$$ROOT._id.fruit",
                "$$ROOT.count"
              ]
            ]
          ]
        }
      },
      usersCount: {
        $sum: "$$ROOT.count"
      }
    }
  },
  {
    "$addFields": {
      "fruitsLie": {
        "$map": {
          "input": "$fruitsLie",
          "as": "item",
          "in": {
            "$arrayToObject": "$$item"
          }
        }
      }
    }
  }
])

Visit the Playground for a hands-on experience.

The query workflow includes the following steps:

  1. Grouping documents by age using $bucket into 4 distinct buckets, (0-30), (31-40), (41-50), and (>50) while aggregating users within each bucket.

  2. Unwinding the users array utilizing the $unwind operator.

  3. Calculating fruit counts within each bucket through the $group stage.

  4. Aggregating counts per bucket into the fruitsLie array with another $group operation.

  5. Converting elements of the fruitsLie array to objects using $arrayToObject.

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

The issue with Express connect-flash only showing after a page refresh instead of instantly displaying on the same page needs to be addressed

Here is the registration route code snippet: router.post("/register", function(req, res){ var newUser = new User({username: req.body.username}); User.register(newUser, req.body.password, function(error, user){ if(error){ req.fl ...

Issue with retrieving the ID of a dynamically created element with jQuery

Whenever I try to execute my function to display the id for a click event of a tag that has items appended dynamically, the alert does not show the id. Instead, it displays 'undefined'. Can anyone help me figure out where I am going wrong? Here ...

Angular animation triggered when a specific condition is satisfied

I am working on an animation within my Angular application @Component({ selector: 'app-portfolio', templateUrl: 'portfolio.page.html', styleUrls: ['portfolio.page.scss'], animations: [ trigger('slideInOut&apo ...

Preventing the detection of a jshint "error"

When creating an object using the constructor X, I later add multiple methods in the file using X.prototype.method = function () {...}. Although technically an assignment statement, it behaves like a function declaration, which typically doesn't requi ...

What is the best way to showcase a single <ul> list in an infinite number of columns?

Utilizing Django on the backend, I aim to showcase the list below in an unlimited number of columns with overflow-x: auto. <ul class="list"> {% for i in skills %} <li>{{i}}</li> {% endfor %} </ul> Example Result: 1 7 ...

Issue: Inability to scroll on div overflow section

My website consists of one static page with an HTML and CSS file. Oddly enough, when testing the page and inputting content into a multiline textarea until it overflows, the browser fails to display a scrollbar. Despite inspecting the div with the id &apos ...

The message "Error: Unknown custom element: <router-view> - have you properly registered the component?" is prompting for a solution

Even though the name is correctly capitalized in all my component instances, I am still encountering an error. After researching similar issues online, it appears that the problem usually revolves around naming discrepancies. However, I have double-checked ...

Ways to switch out event listener when button is deactivated

I find myself in a situation where I need to switch all unauthorized controls on my UI from a hidden state to a disabled state. Additionally, I want to add a tooltip with unauthorized text and have the control display this text when clicked. While I am ab ...

Ensure that the date range picker consistently shows dates in a sequential order

Currently utilizing the vuetify date range picker component https://i.stack.imgur.com/s5s19.png At this moment, it is showcasing https://i.stack.imgur.com/GgTgP.png I am looking to enforce a specific display format, always showing the lesser date first ...

The function is not being executed when using $scope.$apply()

I am in need of a customized click directive that can execute the passed code using scope.$apply(). $(elem).on('click', function(){ scope.$apply(attrs.wdClick); }); Everything works smoothly when I pass something like wd-click="something = ...

The function GetSomething() in sequelize.js is displaying inaccurate values when used in a hasOne relationship, but is showing the correct values in a BelongTo

I'm encountering an issue where trying to fetch a Fluxo through a relationship in my CanaisCadastro results in the GetFluxo() function returning the incorrect row. On the other hand, using the foreign key in a findOne query returns the expected value. ...

Exporting a React parent function to a child component

I have a React project where the rendering works fine, but I am facing an issue with calling a function declared in the parent component. Parent import React, { useState, useMemo, useRef, useCallback, useEffect } from "react"; import { AgGridRe ...

The ins and outs of implementing i18n on an Angular component library

My custom component library is not functioning properly with i18n within my module // To enable Ahead-of-Time compilation, a function must be exported for factories export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(ht ...

The misleading A*(A-star) algorithm inaccurately produces faulty routes and ultimately collapses

I am currently working on implementing the A*(A-star) algorithm in react.js, but I am facing a problem. Whenever the startNode (green) or destinationNode (blue) have more than one neighbour or if there is a cycle in the graph, my program crashes. There see ...

Locate the nested route within one of the child components in React Router that corresponds to a specific id

Picture this scenario where I have a list of routes: const routes = [{ id: "1", path: "animals", children: [{ id: "1.1", path: "birds", children: [{ id: "1.1.1", path: "co ...

Tips for resolving the issue of "Warning: useLayoutEffect does not have any effect on the server" when working with Material UI and reactDOMServer

Encountering an issue with ReactDOMServer and Material UI Theme Provider. Everything seems to be functioning properly, but a persistent error keeps appearing in the console: Warning: useLayoutEffect does nothing on the server, because its effect cannot be ...

Learn how to update a fixed value by adding the content entered into the Input textfield using Material-UI

I made a field using the Input component from material-ui: <Input placeholder="0.00" value={rate} onChange={event => { this.setState({ `obj.rate`, event.target.value }); }} /> Whenever I input a rate into this field, ...

Uploading Files Using the Dropbox API Version 2

Before, I integrated the Dropbox API V1 into my web application to upload files to my personal Dropbox account. The app was configured to use only one specific dropbox account for file uploads. Previous Process: I registered an app on the dropbox develo ...

Guide to running JavaScript in Selenium using JavaScript and retrieving the output

I am currently utilizing JavaScript with the selenium library selenium-webdriver. Below is my code snippet: var chromeCapabilities = webdriver.Capabilities.chrome(); this.driver = new webdriver.Builder() .forBrowser('chro ...

Can you provide tips on identifying children with the same Kineticjs type?

Having a problem with Kineticjs, here is my code: var G1=new Kinetic.Group() var sq=new Kinetic.Rect({ x:0, y:0, name:"sq" }) var line1=new Kinetic.Line({ Points:[0,0,10,10], name:"line1" }) var line2=new Kinetic.Line({ Points:[0,0,50,50], name:"line1" ...