4

I have problems with a mongoose aggregate request.

It's kind of driving me crazy cause I can't find a solution anywhere. I would be very grateful for any support.

The schema:

var EvalSchema = new Schema({
    modified: {type: Date, default: Date.now},
    created : {type: Date, default: Date.now},
    username: {type: String, required: true},
    item: {type: String, required: true},
    criteria: [{
        description: {
            type: String
        },
        eval: {
            type: Number
        }
    }]
});
mongoose.model('Eval', EvalSchema);

and I'm using an aggregation to compute the sum of evaluations for each criterion for a given item.

Eval.aggregate([{
    $match: {
        item: item.id
    }
}, {
    $unwind: "$criteria"
}, {
    $group: {
        _id: "$criteria.description",
        total: {
            $sum: "$criteria.eval"
        },
        count: {
            $sum: 1
        }
    }
}, {
    $project: {
        total: 1,
        count: 1,
        value: {
            $divide: ["$total", "$count"]
        }
    }
}], function(err, result) {
    if (err) {
        console.log(err);
    }
    console.log(result);
});

Result is always empty....

I'm logging all queries that mongoose fire in the application. When I run the query in Mongodb, it returns the correct result.

coll.aggregate([{
    '$match': {
        item: 'kkkkkkkkkkk'
    }
}, {
    '$unwind': '$criteria'
}, {
    '$group': {
        _id: '$criteria.description',
        total: {
            '$sum': '$criteria.eval'
        },
        count: {
            '$sum': 1
        }
    }
}, {
    '$project': {
        total: 1,
        count: 1,
        value: {
            '$divide': ['$total', '$count']
        }
    }
}])

Result:

{
    result: [{
        "_id": "Overall satisfaction",
        "total": 4,
        "count": 1,
        "value": 4
    }, {
        "_id": "service",
        "total": 3,
        "count": 1,
        "value": 3
    }, {
        "_id": "Quality",
        "total": 2,
        "count": 1,
        "value": 2
    }, {
        "_id": "Price",
        "total": 1,
        "count": 1,
        "value": 1
    }],
    ok: 1
}

The model is referencing the correct collection.

Thank you :)

hong4rc
  • 3,999
  • 4
  • 21
  • 40
yosrO
  • 161
  • 1
  • 3
  • 12
  • 1
    Have you checked the value coming from `item.id`? – chridam May 22 '15 at 10:03
  • Yes I did. It contains the correct value. :( – yosrO May 22 '15 at 10:37
  • Check the type of the item.id. Maybe it is not a string. – ZeMoon May 22 '15 at 12:11
  • The type of item.id is a string... :( – yosrO May 22 '15 at 12:29
  • Try the aggregation pipeline without the `$match` operator stage, and see if that returns anything. If it does then there is something wrong with your `item.id` value. – chridam May 22 '15 at 12:58
  • Yes, thank you!!!!!!!!!! it returns something. There seems to be something wrong with item.id. – yosrO May 22 '15 at 13:15
  • What a bad day!!!!!! Issue fixed!!! I was trying to compute the sum before saving the item in evals. :/ – yosrO May 22 '15 at 13:21
  • 4
    For any lost soul who ends up here, in my case the problem was that I had been passing the ids as *Strings* in the `match`. When we passed the ids as *ObjectID*s instead, the aggregation worked. It turns out *ObjectID*s are needed for aggregate even though they are not needed for find. – joeytwiddle Mar 30 '16 at 03:33
  • @joeytwiddle wow that is hard to track down. Thanks!!! – welbornio Apr 24 '16 at 04:22
  • Hi lol I'm back again. This time to say the same problem exists with *Date*s. Your `find()` query might work fine comparing a *Number* against a *Date* in the DB. But for `aggregate()` your `match` had better compare a `new Date()` against a *Date* in the DB. – joeytwiddle Nov 09 '16 at 03:59
  • Wow! For me, the solution was to change `_id` by `id`. Does someone have an explication for that? (solve a problem by making a typo is priceless) – lobodart Mar 01 '17 at 18:04

1 Answers1

15

Your item.id in the $match function is a String, therefore you will need to convert it to an ObjectID, like so:

$match: { item: mongoose.Types.ObjectId(item.id) }

You can refer to this issue on GitHub aggregate for more details.

syang13
  • 151
  • 1
  • 5