Ramsay Lanier
Ramsay Lanier

Reputation: 426

Mongo DB Update Query in Meteor.js

I have the following Meteor.js collection:

Game: { 
  _id: 1,
  rounds: {
     round: {
        number: 1,
        players: {
           player: {
             _id: someId,
             cardSelection: someCard
           }
           player: {
             _id: someId2,
             cardSelection: someCard2
           }
        }
     }
  }

There are some other fields in the collection but these are the important ones. I'm trying to update a player's selection when they click a card. I'm unsure how to do this in MongoDB/Meteor.

So far, I've tried: var currentRound = Games.findOne(gameId).rounds.length;

Games.update({_id: gameId,
              "rounds.round": currentRound,
              "rounds.round.$.players": playerId
              }, 
              {$set: 
                  {"rounds.$.players.$": {id: playerId, selection: selection}}
              }
             );

The problem is that when calling the update, I don't know the rounds position (well I do, its the last round, but the round number changes), and I don't know the player's position inside the Players object inside the Round object.

Any help?

Upvotes: 0

Views: 743

Answers (1)

Neil
Neil

Reputation: 2147

Assuming this structure for a Games document, you cannot update a player directly using the positional update operator.

{
    _id: 1,
    rounds: [{
        number: 1,
        players: [{
            _id: 'someId',
            cardSelection: 'someCard'
        }, {
            _id: 'someId2',
            cardSelection: 'someCard2'
        }]
    }, {
        number: 2,
        players: []
    }]
}

From the mongodb docs:

The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value.

It's not as elegant, but you could set the entire players array. Luckily, underscore makes things easy.

var game = Games.findOne(gameId);
var currentRound = game.rounds.length;

var round = _.findWhere(game.rounds, {number: currentRound});

// find and modify the affected player
round.players = _.map(round.players, function (player) {
  if (player.id === playerId) {
    player.cardSelection = selection;
  }
  return player;
});

Games.update({
  _id: gameId,
  "rounds.number": currentRound
}, {
  $set: {"rounds.$.players": round.players}
});

Alternatively, you could break rounds into a separate collection.

Upvotes: 1

Related Questions