0

I'm building a app where you can vote on user submitted polls. Here's the schema for my polls:

const pollSchema = new Schema({
    userID: String,
    pollQuestion: String,
    pollOptions: [
        {
            name: String,
            quantity: Number
        }
    ]
})

This is the express route that handles incrementing the quantity of a poll option:

app.put('/vote', (req, res) => {
    Poll.update(
        {
            id: req.body.id,
            'pollOptions.name': req.body.selection
        },
        { $inc: { 'pollOptions.$.quantity': 1 } }
    ).then(updatedPoll => {
        console.log('poll', updatedPoll)
        res.send(updatedPoll)
    })
})

here req.body.selection is the option that the user has chosen to vote for.

I basically want the quantity of the user's chosen option to increment by one. This way of updating the database I derived from the answer to this question

When I send a request to this route I get some very unexpected behaviour. For one thing, the database doesn't get updated or changed in any way. The second thing is the updatedPoll is a really bizarre object. Here's what i get from the console.log:

poll { n: 0,
  nModified: 0,
  opTime: 
   { ts: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1510783687 },
     t: 1 },
  electionId: 7fffffff0000000000000001,
  ok: 1 }

The one thing I've tried is include { new: true } as a third parameter after the object with the $inc operator. I doesn't change anything. Can someone please help with this issue?

1
  • 1
    update() does not "return the document" if that is part of what you are expecting, and you need .findOneAndUpdate() to actually return the modified document. The n: 0 in the response though actually means that no such document matches the conditions you are supplying. So check your inputs. Perhaps you should show both the input values you are receiving on the request and the document from the database you expect to match. 0 means there is a mismatch somewhere. Commented Nov 15, 2017 at 22:21

1 Answer 1

1

Thanks to Neil Lunn in the comments, changing my route to the following worked for me:

poll.put('/vote', (req, res) => {
    Poll.findOneAndUpdate(
        {
            _id: req.body.id,
            pollOptions: {
                $elemMatch: { name: req.body.selection }
            }
        },
        { $inc: { 'pollOptions.$.quantity': 1 } },
        { new: true }
    ).then(poll => {
        res.send(poll)
    })
})
Sign up to request clarification or add additional context in comments.

3 Comments

If you think $elemMatch has anything to do with solving here, the it does not. The "pollOptions.name" here is the same expression. See Query an Array Element. You only need $elemMatch for "multiple conditions" on an array element and you only have 'one" condition. Your query failed to match because you fed it incorrect values to match, and not because of anything you changed in the structure of the query.
Hi Neil, thanks once again for the comment. The reason why I changed to $elemMatch is because of this error I was getting when I was using 'pollOptions.name' instead: UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: cannot use the part (pollOptions of pollOptions.name) to traverse the element ({pollOptions: [ { name: "Basketball", quantity: 0, _id: ObjectId('59fefe0638a44c88af288139') }, { name: "Soccer", quantity: 0, _id: ObjectId('59fefe0638a44c88af288138') } ]}) Once I made the change, the error went away.
Can you please clarify your last comment? You said that the error was because I hadn't used $. But then in the comment before that one, you said that given my example $elemMatch is the same as 'pollOption.name' as even though $elemMatch deals with multiple conditions, I'm only using it for one condition. If that's the case then why is the error occurring in one case and not the other? I'm guessing it's not the elemMatch operator per se but the $ that makes the difference?

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.