2

I am using mongoose 4.6.3.

I have the following schema :

var mongoose = require('mongoose');
var User = require('./User');

var TicketSchema = new mongoose.Schema({
    user : { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
},
{
    timestamps: true
});

var DrawSchema = new mongoose.Schema({
  ...
  max_ticket_per_user : { type : Number, required: true },
  tickets: [TicketSchema]
});

module.exports = mongoose.model('Draw', DrawSchema);

How can I count the embedded documents of a certain User ObjectId(user field in TicketSchema) in a Draw's tickets(tickets field in DrawSchema) ? I want to count the tickets of a user for a single draw.

Would it be better to change my schema design ?

Thanks

chridam
  • 100,957
  • 23
  • 236
  • 235
AlexB
  • 3,518
  • 4
  • 29
  • 46

2 Answers2

4

You can use the aggregation framework taking advantage of the $filter and $size operators to get the filtered array with elements that match the user id and its size respectively which will subsequently give you the count.

For an single draw, consider adding a $match pipeline operator as your initial step with the _id query to filter the documents in the collection.

Consider running the following aggregation pipeline to get the desired result:

Draw.aggregate([
    { "$match": { "_id": drawId } },
    {
        "$project": {
            "ticketsCount": {
                "$size": {
                    "$filter": {
                        "input": "$tickets",
                        "as": "item",
                        "cond": { "$eq": [ "$$item.user", userId ] }
                    }
                }
            }
        }
    }
]).exec(function(err, result) {
    console.log(result);
});
chridam
  • 100,957
  • 23
  • 236
  • 235
  • Great answer. I get the information I need but I only want to aggregate on a draw with a given id. – AlexB Oct 09 '16 at 02:12
  • what I get as a response is all the draws id with their count for the userId. I only want to aggregate on a single draw id – AlexB Oct 09 '16 at 02:22
  • @AlexB You'd need a $match pipeline query to filter your documents, as I've shown in the update above. – chridam Oct 09 '16 at 07:08
  • FWIW, Most cloud based Mongodb platforms, such as every cloud based solution provided by Heroku, doesn't support mongo version `3.4` yet, and hence the `$filter` command won't work – Augie Gardner Feb 28 '17 at 00:59
2

You can pass the .count() deep parameters like any other query object:

Draw.count({'tickets.user._id' : userId}, console.log);

Make sure the userId variable is an ObjectId. If it's a string, do this:

const ObjectId = require('mongoose').Types.ObjectId;
let userId = new ObjectId(incomingStringId);
Paul
  • 35,689
  • 11
  • 93
  • 122