speak speak - 4 years ago 103
Javascript Question

Mongoose update conditions matching wrong object

Model Schema

const PollSchema = new Schema({
title: { type: String, trim: true, required: true },
choices: [
{
title: { type: String, trim: true, required: true },
votes: { type: Number, default: 0, min: 0 },
}
],
date: { type: Date, default: Date.now },
url: { type: String, required: true, unique: true },
})


Update call

async vote (pollId, choiceId, unvoteId = '') {
try {
await pollModel.update(
{ '_id': pollId, 'choices._id': choiceId },
{ $inc: { 'choices.$.votes': 1 } },
)

if (unvoteId) {
await pollModel.update(
{
"$and": [
{ '_id': pollId },
{ 'choices._id': unvoteId },
{ 'choices.votes': { $gt: 0 } }
],
},
{ $inc: { 'choices.$.votes': -1 } },
)
}

return await pollModel.findById(pollId)
} catch (e) {
throw new ApiError(
500, 'Error: Poll:Vote', e
)
}
}


I have been trying a plethora of combinations trying to get this to work. Voting +1 works as intended, but when trying to -1, the query conditions are not properly matched. I have tried
$and
,
$elemMatch
, plain object with the 3 conditions (according to the docs this is sufficient and implicitly means
and
too.

Whenever I send through an unvoteId, no matter which
_id
I choose in the array, it will always match the FIRST element that has
$gt 0
votes. It is as if
choices._id
is completely ignored, and as soon as it meets a choice that has > 0 votes, it returns that for the
$
positional param.

Is this intended? I assumed
$and
would only match if all 3 conditions were satisfied.

What I am trying to do is update the votes atomically using
$inc
, while also ensuring that when someone votes, they cannot bring the value below 0. As the mongoose validators do not get run during updates, I am trying to validate this via the query itself.

Answer Source

Try something like this.

pollModel.update({
    _id: pollId,
    choices: {
        $elemMatch: {
            _id: unvoteId,
            votes: {
                $gt: 0
            }
        }
    }
}, {
    $inc: {
        "choices.$.votes": -1
    }
})
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download