1

I have this mongoDB document structure:

Game = {
  _id: 'randomObjectId',
  players: [Array of players ObjectIds],
  maxPlayers: 2,
  status: 'created' (or 'fully-booked')
}

When a new player joins the game I want to add him to the players array and change the status of the game to fully-booked only if this condition is met: players.length < maxPlayers.

To recap:

  • Check inside the DB(using the query) if players.length < maxPlayers;
  • If yes update the document
  • If no send back an error response (optional)

Without this check it's easy to make the query using:

Game.findByIdAndUpdate('randomObjectId', {
  $addToSet: {
    players: 'playerObjId'
  },
  gameStatus: 'fully-booked'
}, {
  new: true
})

What I don't know is how to add this condition to this (or other type of) query. Any help is appreciated. Thanks

11
  • Your condition is broken, btw. If implemented as requested, it'd mark a game as "fully booked" when the game gets its first player (1 of 2). I suggest you separate marking as "fully booked" from adding players to the game. Commented Jun 3, 2021 at 15:10
  • And to your general question, "how do I add conditions to updates", I'd use findAndModify here. Commented Jun 3, 2021 at 15:35
  • Please check docs.mongodb.com/manual/reference/operator/aggregation/set/… Commented Jun 3, 2021 at 15:38
  • @AlexBlex: aggregation pipeline's $set is irrelevant here, though? Or am I missing something? Commented Jun 3, 2021 at 16:05
  • @SergioTulentsev the pipeline $set makes it possible to do conditional update with docs.mongodb.com/manual/reference/operator/aggregation/cond/… operator. Commented Jun 3, 2021 at 16:13

1 Answer 1

1

you can try an aggregation pipeline update like the following. however, if already fully booked, the command will return a null. also note that if you try to add a player id that already exists in the array, it won't be added.

db.collection.findOneAndUpdate(
    {
        _id: someObjectId,
        $expr: {
            $lt: [{ $size: "$players" }, "$maxPlayers"]
        }
    },
    [
        {
            $set: {
                players: { $setUnion: ["$players", [newPlayerObjectId]] }
            }
        },
        {
            $set: {
                status: {
                    $cond: {
                        if: { $lt: [{ $size: "$players" }, "$maxPlayers"] },
                        then: "created",
                        else: "fully-booked"
                    }
                }
            }
        }
    ],
    {
        returnNewDocument: true
    })
Sign up to request clarification or add additional context in comments.

2 Comments

$set throws an error but the $expr in the first part prevents me from adding an extra player, so it works in the end. Thanks
@GabrielLupu works for me without an issue. see here: streamable.com/linm5c that is in mongo shell though. i'm not sure if mongoose has support for pipeline updates.

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.