简体   繁体   中英

How can I get the total sum ($sum) of an array from a nested field?

I need the total sum of all the elements in an array that is nestet in my schema. This is the schema:

const mongoose = require('mongoose');

let historySchema = new mongoose.Schema({
    time: {
        type:String
    }
})

//users schema

let userSchema = new mongoose.Schema({
    name:{
        type:String,
        
    },
    dob:{
        type:String,
        
    },
    email:{
        type:String,
        
    },
    noOfpeopleClimbing:{
        type: Number,
        default:0
    },
    details:{
        type:String,
        
    },
    status:{
        type: Boolean,
        default: false
    },
    timeIn:{
        type: Number,
        default: 0
    },
    timeOut:{
        type: Number,
        default: 0
    },
    timeFinal:{
        type: Number,
        default: 0
    },
    history:[{
        
        time:{
            type: Number
        },
        date:{
            type:Date,
            default:Date.now()
        },
        climbers:{
            type: Number
        },
        names:{
            type: String
        }
    }]
})
let User = module.exports = mongoose.model("User", userSchema);

The nested field in disscusion is:

history:[{
    time:{
        type: Number
}]

And the find method is:

app.get('/user/:id', function(req,res){

    Users.findById(req.params.id, function(err, users){

        res.render("user",
        {
        title:users.name,
        users:users,
        });
    })
})

Can I attach to my find route an aggregate with $sum in order for me to send the data with the sum to my render view?.

For example totalTimeHistory:$sum aggregate data .

Use the following snippet below:

const result = Users.aggregate([
{
   $match: {
     //Your find block here
   }
},
{
    $unwind: "$history"
},
{
    $project: {
        totalTimeHistory: { $sum: "$history.time"}
    }
}
])

Try this query:

db.collection.aggregate([
  {
    "$match": {
      "name": "name" //or whatever you want
    }
  },
  {
    "$project": {
      "total": {
        "$sum": "$history.time"
      }
    }
  }
])

In this way you don't need $unwind

Example here

db.getCollection('users').aggregate([
{
    $match: {
        <your find query goes here>
    }
},
{
    $unwind: '$history'
},
{
    $group: { 
        _id: <your user object id (or) null>, 
        history: { $push: "$$ROOT.history" }
    }
},
{
    $addFields: {
        totalSumOfHistoryTypes: { $sum: "$history.type" }
    }
},

])

your output will look like在此处输入图片说明

explanation:

$match: to find in the collection

$unwind: to unwind the history array so that the values of history can be grouped

$group: here we have created an array called history and pushed the history object($$ROOT.history) into it

$addFiled: used to add a new field which is not present on the schema

Hope this explains cheers

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM