Dread Boy
Dread Boy

Reputation: 722

Mongoose doesn't save data while reporting them being saved

I'm having a problem saving some data to Mongo using mongoose.

In my database module I'm doing:

  self.addMove = function (gameId, move, callback) {
    Game.findById(gameId, function (err, game) {
      if (err)
        callback(err);
      else {
        game.newMove = move; //apply new move
        game.save(Game.transformState(callback)); //save the game
      }
    });
  };

where newMove is defined as virtual method in GameSchema as

GameSchema.virtual('newMove').set(function (move) {
  if (move.player !== move.piece[0])
    return;
  if (allowedMove(move)) { //if piece is allowed to move
    var from = positionToIndex(move.from),
      to = positionToIndex(move.to);
    this._field[to] = this._field[from]; //move it
    this._field[from] = "";
  }
});

and transformState as static method

GameSchema.statics.transformState = function (callback) {
  return function (err, data) {
    if (err)
      callback(err);
    else
      callback(null, {
        _id: data._id,
        moves: data.moves,
        field: data.field //data.field transforms 1D array into 2D client-useable array
      });
  };
};

How I call addMove:

socket.on('addMove', function (msg) {
  console.log('New move: ' + msg);
  var msg = JSON.parse(msg);
  db.addMove(msg._id, msg.move, function (err, data) {
    if(!err)
      io.emit('getState', JSON.stringify(data));
  });
});

As requested, my GameSchema:

GameSchema = new Schema({
  moves: [MoveSchema],
  _field: {
    type: [String],
    default: ["WR", "WN", "WB", "WQ", "WK", "WB", "WN", "WR", "WP", "WP", "WP", "WP", "WP", "WP", "WP", "WP", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "BP", "BP", "BP", "BP", "BP", "BP", "BP", "BP", "BR", "BN", "BB", "BQ", "BK", "BB", "BN", "BR"]
  }
})

And as a bonus, this is how I request game state second time:

//sockets.js
socket.on('getState', function (msg) {
  console.log('User requested game state!');
  var msg = JSON.parse(msg);
  db.getGame(msg._id, function (err, data) {
    if(!err)
      io.emit('getState', JSON.stringify(data));
  });
});

//database.js
self.getGame = function (id, callback) {
  Game.findById(id, Game.transformState(callback));
};

As you can see, each time I get new move from client I modify current game field and save that game. When I save it with game.save(Game.transformState(callback)); it is "saved" which means data in callback are correct. But if I try to request game state again, I can see it's not saved. I also tried checking MongoDB manually and indeed is not saved. What I'm trying to explain is that in line game.save(Game.transformState(callback)); function callback is executed with updated game state and I can see it on client but the state is actually not saved in database.

Upvotes: 0

Views: 519

Answers (1)

Dread Boy
Dread Boy

Reputation: 722

Apparently, mongoose doesn't detect field was changed if you modify arrays directly. To trigger detection I used this.markModified('_field');

There are some other methods to do this I found out later: Mongoose: assign field of type 'array of Strings'

Upvotes: 2

Related Questions