Organize by Day and Total Item Quantity, with Item Names as the Key Outputs

I've been experimenting with the following examples: https://docs.mongodb.com/manual/reference/operator/aggregation/push/ and https://docs.mongodb.com/manual/reference/operator/aggregation/addToSet/

Here are some sample documents to work with:

{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }
{ "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }
{ "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") }
{ "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") }
{ "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }

I'm looking for a combination of both examples. In the push example, the output appears as follows:

{
    "_id" : { "day" : 46, "year" : 2014 },
    "itemsSold" : [
        { "item" : "abc", "quantity" : 10 },
        { "item" : "xyz", "quantity" : 10 },
        { "item" : "xyz", "quantity" : 5 },
        { "item" : "xyz", "quantity" : 10 }
    ]
}
{
    "_id" : { "day" : 34, "year" : 2014 },
    "itemsSold" : [
        { "item" : "jkl", "quantity" : 1 },
        { "item" : "xyz", "quantity" : 5 }
    ]
 }
 {
     "_id" : { "day" : 1, "year" : 2014 },
     "itemsSold" : [ { "item" : "abc", "quantity" : 2 } ]
 }

In the $addToSet example, the results look like this:

{ "_id" : { "day" : 46, "year" : 2014 }, "itemsSold" : [ "xyz", "abc" ] }
{ "_id" : { "day" : 34, "year" : 2014 }, "itemsSold" : [ "xyz", "jkl" ] }
{ "_id" : { "day" : 1, "year" : 2014 }, "itemsSold" : [ "abc" ] }

My desired output format would be:

{ "_id" : { "day" : 46, "year" : 2014 }, "itemsSold" : { "xyz": 25, "abc": 10 } }
{ "_id" : { "day" : 34, "year" : 2014 }, "itemsSold" : { "xyz": 5, "jkl": 1 ] }
{ "_id" : { "day" : 1, "year" : 2014 }, "itemsSold" : { "abc": 2 } }

Is there a way to achieve this format? Any tips or guidance would be greatly appreciated.

Answer №1

After reviewing your data, it seems you require two $group stages to first aggregate by "item" and then store those item details in an array.

Depending on the version of MongoDB at your disposal, further processing may vary. For MongoDB 3.6 (or from 3.4.7), consider utilizing $arrayToObject to reshape the data as needed:

db.collection.aggregate([
  { "$group": {
    "_id": {
      "year": { "$year": "$date" },
      "dayOfYear": { "$dayOfYear": "$date" },
      "item": "$item"
    },
    "total": { "$sum": "$quantity" }
  }},
  { "$group": {
    "_id": {
      "year": "$_id.year",
      "dayOfYear": "$_id.dayOfYear"
    },
    "itemsSold": { "$push": { "k": "$_id.item", "v": "$total" } }
  }},
  { "$sort": { "_id": -1 } },
  { "$addFields": { 
    "itemsSold": { "$arrayToObject": "$itemsSold" }
  }}
])

For earlier versions, a post-processing step can achieve the same outcome since aggregation is completed before the final stage:

db.collection.aggregate([
  { "$group": {
    "_id": {
      "year": { "$year": "$date" },
      "dayOfYear": { "$dayOfYear": "$date" },
      "item": "$item"
    },
    "total": { "$sum": "$quantity" }
  }},
  { "$group": {
    "_id": {
      "year": "$_id.year",
      "dayOfYear": "$_id.dayOfYear"
    },
    "itemsSold": { "$push": { "k": "$_id.item", "v": "$total" } }
  }},
  { "$sort": { "_id": -1 } }
]).map( d => Object.assign( d, 
  { 
    itemsSold: d.itemsSold.reduce((acc,curr) =>
      Object.assign(acc, { [curr.k]: curr.v }),
      {}
    )
  }
))

Both methods yield the desired result:

{
        "_id" : {
                "year" : 2014,
                "dayOfYear" : 46
        },
        "itemsSold" : {
                "xyz" : 25,
                "abc" : 10
        }
}
{
        "_id" : {
                "year" : 2014,
                "dayOfYear" : 34
        },
        "itemsSold" : {
                "jkl" : 1,
                "xyz" : 5
        }
}
{
        "_id" : {
                "year" : 2014,
                "dayOfYear" : 1
        },
        "itemsSold" : {
                "abc" : 2
        }
}

While new aggregation features can be beneficial, often reshaping tasks are more efficiently handled through client-side processing.

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

Add a fresh text field with the click of a button and delete it with another button in Laravel 4

My form includes two fields: phone and email, as shown in the image below. By clicking on the plus button, I would like to add an additional text field to the form below the button. Similarly, by clicking on the minus button, I want to remove the text fie ...

Utilizing jQuery to place an element beside another and maintain its position

I need ElementA to be positioned next to ElementB as shown in this example. The key difference is that I want ElementA to move along with ElementB if the latter is relocated. Is there a way to keep a specific element fixed to another one? Re-calculating ...

Pagination in MongoDB with grouped items

In the process of integrating a messaging module into an existing web application, the messages are stored in a MongoDB database using a specific data structure: { id: "", inResponseToMessageId: "" to: [] cc: [] bcc: [] subject: "" body: "" ...

Sending a Large File with Axios

I am facing a challenge while trying to upload a large JSON file containing at least 400,000 objects into my database. When I attempt to post only 20,000 objects at a time, everything works smoothly, indicating that the issue lies with the size of the JSON ...

Conventions for ObjectID

How can I generate unique IDs with a specific convention? Instead of the standard format like "538cd180e381f20d1c1cd2a2", I am looking to start my IDs with a consonant, for example: "p38cd180e381f20d1c1cd2a2". Is there a way to achieve this using the "ne ...

Is there a way to utilize nodemon without having to install it through npm?

I'm having trouble with my network not allowing me to use npm install. Is there another way for me to install and use nodemon? I've noticed that Node only runs after setting PATH variables on Windows. I attempted to set the path for nodemon, but ...

Issue with replacing fragment shader in three.js not resolved in versions above 131

I have created an example showcasing the replacement of standard material (fragment and vertex shader) that was functioning properly in three.js versions prior to r131. However, in releases above 131, the changes made to the fragment shader are no longer w ...

When using selenium with python, the function excecute_script('return variable') may not technically return variables, even though the variable does exist

My attempt to retrieve a variable from javascript code using selenium is encountering difficulties. Despite the presence of the variable (confirmed by inspecting the source code before executing the script), the command driver.execute_script('return v ...

Having trouble loading static assets in next.js framework

I am currently using Next.JS to develop a small landing page that features videos and images. To house these static assets, I decided to create a static folder and call the videos/images from there. However, I have encountered an issue where Next is unabl ...

How to Create a Speech Bubble in SVG Using SnapSVG

In the process of developing a chat program, I have animated figures moving across the screen engaging in conversations. One crucial aspect I am yet to implement is creating scalable speech bubbles for when users interact. Being relatively new to SVG and ...

What is the correct method for utilizing key value parameters during an upsert operation?

function insertUpdateDocument(database, collection, keyValuePair, data) { database.collection(collection).updateOne( keyValuePair, { $set: data }, { upsert: true } ); } I would like to create a function similar to the one a ...

Manipulate a nested document within a deeply nested object using Mongoose

I am currently facing the challenge of updating an object that is nested inside an array within another array. Here is an overview of my schema: const quizzerSchema = mongoose.Schema( { title: { type: String, }, imgUrl: { type: St ...

What is the process for locating JavaScript project options in Eclipse 2020-06?

I recently installed the Eclipse IDE for Web and JavaScript Developers package version 2020-06. However, I am unable to find the "JavaScript Project" option when trying to create a new project by going to "File >> New". Any suggestions on how to reso ...

Modifying material in Three.js

My method for selecting geometry involves using the numbers on my keyboard, as shown below: if(keyboard.pressed("1")){ obj = torus; } This allows me to toggle their visibility: if(keyboard.pressed("a")){ THREE.SceneUtils.traverseHierarchy( obj, fu ...

Error in compiled.php on line 7772: Laravel throwing a RuntimeException when sending HTTP requests from Angular

Hey there, I've been encountering an error intermittently while using Angular $http methods with a Laravel API. Can someone please explain what this error means and suggest potential solutions? I've shared the error log on CodePen for easier refe ...

Display the data from the selected cell using jQuery

Is there a way to update the following code: $(".rank").click(function(event){ alert(this.id); }); so that it alerts the value inside of <td class="rank"></td> rather than its id? ...

Protractor and Jasmine fail to fulfill the promise of retrieving a webpage title

I am facing an issue with my protractor/jasmine test code where it only prints out 1 and 2, then hangs and times out. It seems like there might be a problem with the click() action on the button element or the promise on the getTitle method of the browser ...

Guide on adjusting CSS in Vue

Here's the HTML element that I'm working with: <div id="scrollbar" style="background-color: #000;" v-bind:style="{ height : scrollbarheight + 'px' }" ></div> I have been attempting to adj ...

Updating an array within an object that is nested inside another array in MongoDB

I am faced with the task of modifying an array of objects within another array, and I am struggling to figure out how to achieve this. The position of the element in the array is stored in a variable rather than a string, which complicates things for me. I ...

Node(Meteor) experiencing a memory leak due to setTimeout

I have encountered an unusual memory leak associated with the use of setTimeout. Every 15 seconds, I execute the following code using an async function that returns an array of promises (Promise.all). The code is supposed to run again 15 seconds after all ...