G.Mounika
G.Mounika

Reputation: 425

Type Error: collection.group is not a function in mongoose

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

Answers (1)

Neil Lunn
Neil Lunn

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

Related Questions