Update field in sub document mongoose Update field in sub document mongoose mongoose mongoose

Update field in sub document mongoose


Since this is an embedded document it is quite easy:

If you want to update a document that is the first element of the array, that doesn't have a userId

db.collection.update(    {         "status": 0,        "countPlayers": {"$lt": 10 },        "companies.userId": {"$exists": false }    },    { "$set": {"companies.$.userId": userId } })

Which would be nice, but apparently this doesn't match how MongoDB processes the logic and it considers that nothing matches if there is something in the array that does have the field present. You could get that element using the aggregation framework but that doesn't help in finding the position, which we need.

A simplified proposal is where there are no elements in the array at all:

db.collection.update(    {         "status": 0,        "countPlayers": {"$lt": 10 },        "companies.0": {"$exists": false }    },    { "$push": {"userId": userId } })

And that just puts a new thing on the array.

The logical thing to me is that you actually know something about this entry and you just want to set the userId field. So I would match on the login:

db.collection.update(    {         "status": 0,        "countPlayers": {"$lt": 10 },        "companies.login": login,    },    { "$set": {"companies.$.userId": userId } })

As a final thing if this is just updating the first element in the array then we don't need to match the position, as we already know where it is:

db.collection.update(    {         status: 0,         countPlayers: {"$lt": 10 }    },    { $set: { "companies.0.userId": userId  } })

Tracing back to my logical case, see the document structure:

{     "_id" : ObjectId("530de54e1f41d9f0a260d4cd"),    "status" : 0,    "countPlayers" : 5,    "companies" : [         { "login" : "neil" },        { "login" : "fred", "userId" : ObjectId("530de6221f41d9f0a260d4ce") },        { "login": "bill" },     ] }

So if what you are looking for is finding "the first document where there is no userId", then this doesn't make sense as there are several items and you already have a specific userId to update. That means you must mean one of them. How do we tell which one? It seems by the use case that you are trying to match the information that is there to an userId based on information you have.

Logic says, look for the key value that you know, and update the position that matches.

Just substituting the db.collection part for your model object for use with Mongoose.

See the documentation on $exists, as well as $set and $push for the relevant details.


Big thanks.

I solved his problem

exports.joinGame = function(req, res) {  winston.info('start method');  winston.info('header content type: %s', req.headers['content-type']);  //достаем текущего пользователя  var currentUser  = service.getCurrentUser(req);  winston.info('current username %s', currentUser.username);  //формируем запрос для поиска игры  var gameQuery = {"status": 0, "close": false};  gameChamp.findOne(gameQuery, {}, {sort: {"createdAt": 1 }}, function(error, game) {    if (error) {      winston.error('error %s', error);      res.send(error);    }    //если игра нашлась    if (game) {      winston.info('Append current user to game: %s', game.name);      //добавляем userId только к одной компании      var updateFlag = false;      for (var i=0; i<game.companies.length; i++) {        if (!game.companies[i].userId && !updateFlag) {          game.companies[i].userId = currentUser._id;          updateFlag = true;          winston.info('Credentials for current user %s', game.companies[i]);          //если пользовател последний закрываем игру и отправляем в bw, что игра укомплектована          if (i == (game.companies.length-1)) {            game.close = true;            winston.info('game %s closed', game.name);          }        }      }      //сохраняем игру в MongoDB      game.save(function(error, game) {        if (error) {          winston.error('error %s', error);          res.send(error);        }        if (game) {          res.send({ game: game })          winston.info('Append successful to game %s', game.name);        }      });    }  });}