Reputation: 425
Here is the data in telecalling collection
{
"product": "a",
"demo": true,
"followups": [
{
"followup": "2017-05-03T07:54:41.085Z",
"actiondone": "enquiry"
},
{
"followup": "2017-05-05T07:54:41.085Z",
"actiondone": "followup"
}
],
"createdAt": "2017-05-03T07:54:41.085Z",
},
{
"product": "b",
"demo": false,
"followups": [
{
"followup": "2017-05-04T07:54:41.085Z",
"actiondone": "followup"
},
{
"followup": "2017-05-10T07:54:41.085Z",
"actiondone": "installation"
}
],
"createdAt": "2017-05-04T07:54:41.085Z",
},
{
"product": "a",
"demo": false,
"followups": [
{
"followup": "2017-05-06T07:54:41.085Z",
"actiondone": "followup"
}
],
"createdAt": "2017-05-06T07:54:41.085Z",
}
Here I need to group by product and get how many demos, enquiries, followups and installations are done.
Here is the controller for that
var mongoose = require('mongoose');
var telecalling = mongoose.model('telecalling');
summaryReport: function(request,response){
telecalling.group({
key: {product: 1},
cond: {"createdAt": {"$gte": new Date(request.body.fromdate),"$lte": new Date(request.body.todate)}},
reduce: function(curr, result) {
if(curr.demo==true){
result.demos++;
}
var fups = curr.followups;
fups.forEach(allCounts);
function allCounts(fup){
var action = fup.actiondone.toLowerCase()
if(action=='enquiry'){
result.enquiries++;
}
if(action=='followup'){
result.followups++;
}
if(action=='installation'){
result.installations++;
}
}
},
initial: {enquiries: 0, followups: 0, installations: 0}
}, function(err,res){
if(err){
response.json(err);
}
else{
response.json(res);
}
});
}
I'm getting TypeError: telecalling.group is not a function. If I execute this in shell I'm getting the result as
[
{
"product" : "Fair Automobiles",
"enquiries" : 7,
"followups" : 15,
"installations" : 0,
"demos" : NaN
},
{
"product" : "Fair Fertilizers",
"enquiries" : 1,
"followups" : 0,
"installations" : 0
}
]
Where am I doing wrong. Please help me out.
Upvotes: 0
Views: 1434
Reputation: 151190
Mongoose models do not have a .group()
method. You really should be using .aggregate()
for most cases, so it's worth learning.
Heres the equivalent operation:
telecalling.aggregate([
{ "$match": {
"createdAt": {
"$gte": new Date(request.body.fromdate),
"$lte": new Date(request.body.todate)
}
}}
{ "$group": {
"_id": "$product",
"demos": {
"$sum": {
"$cond": {
"if": { "$eq": [ "$demo", true ] },
"then": 1,
"else": 0
}
}
},
"enquries": {
"$sum": {
"$size": {
"$filter": {
"input": "$followups",
"as": "f",
"cond": { "$eq": [ "$$f.actiondone", "enquiry" ] }
}
}
}
},
"followups": {
"$sum": {
"$size": {
"$filter": {
"input": "$followups",
"as": "f",
"cond": { "$eq": [ "$$f.actiondone", "followup" ] }
}
}
}
},
"installations": {
"$sum": {
"$size": {
"$filter": {
"input": "$followups",
"as": "f",
"cond": { "$eq": [ "$$f.actiondone", "installation" ] }
}
}
}
}
}}
],function(err,response) {
// work with result
})
First you have a $match
which is exactly the same as the query argument.
Next since your operation is fairly simple, you have a single $group
stage using the _id
key of "product"
just like your .group()
does.
The "demos"
field has a logical value that you can switch with a numeric one using the $cond
operator and then pass to $sum
.
The actual fields are a little tricky to understand at first, but basically you use $filter
on the array to find the items that match the specified "actiondone"
, then use $size
to get the "size" of the filtered list and pass that to the $sum
accumulator to count.
Upvotes: 1