2
votes

I have a meteor app and I want to update a mongo document from the server side with the positional operator. I also want to increment the value voted.

My mongo document looks like:

{
    _id: "yBonLeLPTcffxJwY9",
    endDate: "someDate",
    name: "Foo",
    options: [
      {
        name: "bar",
        voted: 1,
        usersId: ["yBonLeLPTczzaJwY9"]
      }
    ]
}

And my update request looks like:

Votes.update({
      _id: mongoId,
      'options.name': voteName
    }, {
      $inc: {'options.$.voted': 1},
      $push: {'options.$': {usersId: userId}}
  });

I got this error message:

MongoError: The field 'options.1' must be an array but is of type Object in document {_id: "yBonLeLPTcffxJwY9"}

I found on several forums that there is a limitation in minimongo that affects the use of the positional operator and the increasing value.

1

1 Answers

0
votes

The error told you the right thing. You included a "document" and not a plain member. So the syntax is a little different:

Votes.update({
      _id: mongoId,
      'options.name': voteName
    }, {
      $inc: {'options.$.voted': 1},
      $push: {'options.$.usersId': userId}
  });

So reference the inner field fully in "dot notation" to the array you want to add to with $push. That resolves the error.

May I also suggest that in a "voting" system you should instead be checking that usersId array for the entry first:

Votes.update({
      _id: mongoId,
      'options.name': voteName,
      'options.usersId': { '$ne': userId }
    }, {
      $inc: {'options.$.voted': 1},
      $push: {'options.$.usersId': userId}
  });

That way your $inc does not increase when someone who has voted submits a vote again, nor are they added to the array when they are already there.