lamfete
lamfete

Reputation: 151

nodejs + mongoose - query aggregate

I have this schema on my node.js app. I'm using mongoose:

var todoSchema = new Schema({
  task: String,
  description: String,
  date: Date,
  status: String,
  checklist: Boolean,
  user: String
});

I want to get this result, so I can pass it into google chart and display it on chart:

[
  {
    "user": "A",
    "detail" :
    [
      "open" : 3,
      "progress" : 5,
      "done" : 7
      "archive" : 10
    ]
  },
  {
    "user": "B",
    "detail" :
    [
      "open" : 4,
      "progress" : 9,
      "done" : 14
      "archive" : 12
    ]
  }
]

But my query looks wrong:

Todo.find().distinct( "user", function(err, users){
    Todo.find({"user": {"$in": users}}, function(err, todo){
      if (err)
        res.send(err);

      var finalResult = [];
      finalResult.push(todo);
      res.send(finalResult);
      //res.send(todo);
    });
  });
});

Anybody can help me, please? Really appreciated your help.

Upvotes: 1

Views: 733

Answers (2)

chridam
chridam

Reputation: 103345

Use aggregation framework and run the following aggregation pipeline which uses two $group and $project pipeline steps; the first one is to group your documents by the user field and use the $cond operator in the $sum accumulator operator expression to evaluate the counts based on the status field. The second $group pipeline step will add the detail array by using the accumulator operator $push that returns an array of expression values for each group. The last step $project will modify the document fields by renaming the _id field to user:

var pipeline = [
    { 
        "$group": { 
            "_id": "$user",             
            "open_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$status", "open" ] }, 1, 0 ]
                }
            },
            "progress_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$status", "progress" ] }, 1, 0 ]
                }
            },
            "done_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$status", "done" ] }, 1, 0 ]
                }
            },
            "archive_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$status", "archive" ] }, 1, 0 ]
                }
            } 
        }  
    },
    {
        "$group": {
            "_id": "$_id",            
            "detail": {
                "$push": {
                    "open": "$open_count",
                    "progress": "$progress_count",
                    "done": "$done_count",
                    "archive": "$archive_count"
                }
            }
        }
    },
    {
        "$project": {
            "_id": 0, "user": "$_id", "detail": 1
        }
    }
];


Todo.aggregate(pipeline, function (err, result){
    if (err) res.send(err);
    console.log(JSON.stringify(result, undefined, 4));
    res.send(result);
})

Upvotes: 3

vmkcom
vmkcom

Reputation: 1668

This should work for you. Simply gets all of your todos. Do not forget to return when handling errors

Todo.find({}, function(err, todos){
    if (err)
        return res.send(err);

    res.send(todos)
})

Upvotes: 0

Related Questions