1

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.

2
  • You are specifing "pic" field inside distinct method, but I don't see that field inside your todoSchema. Do you get any error? Commented Nov 23, 2015 at 13:07
  • @NikolaB. sorry for the typo. I already edited my post and changed it into user. thank you for the correction. Commented Nov 23, 2015 at 13:31

2 Answers 2

3

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);
})
Sign up to request clarification or add additional context in comments.

3 Comments

thank you for your help. I'm sorry for my stupidity to asking question like that, I'm still learning about mongodb and nodejs. Really appreciate your help.
@lamfete No worries, always happy to help :-) If this answers your question, consider marking the answer as accepted. You can do so by clicking on the check mark beside the answer to toggle it from greyed out to filled in. You may change which answer is accepted, or simply un-accept the answer, at any time. Note, there is no obligation in accepting the answer, but feel free to do so as that's the norm around here. Also consider doing the exercise to your other questions. Welcome to StackOverflow!
I'm sorry, I don't know before to toggle check list beside the answer. I already clicked it for this post and my post before which is you answered it too :)
0

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)
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.