Atenean1
Atenean1

Reputation: 92

Adding a separate document in an aggregation output for sum totals of other output document fields in MongoDB

I currently have an aggregation query with three stages that produces the following output documents (these are just two out of many):

{
        "title" : "hr",
        "num_files" : 420,
        "affected_files" : 0,
        "to_encrypt" : 6,
        "affected_file_percentage" : 0
}
{
        "title" : "mktng",
        "num_files" : 69,
        "affected_files" : 2,
        "to_encrypt" : 5,
        "affected_file_percentage" : 0.02898550724
}

I want to add a last document that has the following output:

{
        "title" : "total",
        "num_files" : [sum of all files],
        "affected_files" : [sum of all affected files],
        "to_encrypt" : [sum of all files to be encrypted],
        "affected_file_percentage" : [total percentage]
}

I couldn't find anything in the aggregation functions as adding another stage in the pipeline to sum everything wouldn't allow me to show the individual documents. I want to show both those and the grand total in the output. How could this be done?

Upvotes: 2

Views: 1020

Answers (1)

turivishal
turivishal

Reputation: 36114

You can use $facet, to separate both in different fields,

  • result: [] will get all documents from root
  • total to create separate array with one object of total, $group to sum numbers field
db.collection.aggregate([
  {
    $facet: {
      result: [],
      total: [
        {
          $group: {
            _id: null,
            title: { $first: "total" },
            num_files: { $sum: "$num_files" },
            affected_files: { $sum: "$affected_files" },
            to_encrypt: { $sum: "$to_encrypt" },
            affected_file_percentage: { $sum: "$affected_file_percentage" }
          }
        }
      ]
    }
  }
])

Playground


If you want just an object for total in root then try,

  • $facet and $group are same as above query, after that add below stages
  • $project to concat both arrays using $concatArrays
  • $unwind deconstruct root array
  • $replaceWith to replace root object in root
db.collection.aggregate([
  {
    $facet: {
      result: [],
      total: [
        {
          $group: {
            _id: null,
            title: { $first: "total" },
            num_files: { $sum: "$num_files" },
            affected_files: { $sum: "$affected_files" },
            to_encrypt: { $sum: "$to_encrypt" },
            affected_file_percentage: { $sum: "$affected_file_percentage" }
          }
        }
      ]
    }
  },
  {
    $project: {
      root: { $concatArrays: ["$result", "$total"] }
    }
  },
  { $unwind: "$root" },
  { $replaceWith: "$root" }
])

Playground

Upvotes: 1

Related Questions