Search code examples
javascriptnode.jsmongodbmongoosemongoose-schema

Unable to update User games property when user creaties a new game mongoose


I'm working on an app where users can create and account and make trivia games. User has a property called games which is a collection of Game id's that that User instance has created. When I create a Game instance, before I return the response (JSON of new Game instance), I find the User instance and use a User schema method to add the newly created Games id to the collection of game ids in the User's games property. It seems to work when I create a game, I was able to log the instance of User with the array reflecting the newly added Game id.

But then when I try to get the User via localhost:4000/users/USER_ID the games property remains empty.

Here is my User Model.

const mongoose = require("mongoose");
const validator = require("validator");
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const Schema = mongoose.Schema;

let User = new Schema({
  username: {
     type: String, required: true, trim: true, default: null,
     unique: true
  },
  password: {
     type: String, required: true, trim: true, default: null
  },
  games:{
     type: Array, required: false, default: []
  }
});

User.methods.addGame = async function(id) {
  const user = this;
  var games = user.games;
  games.push(id);
  user.games = games;
  user.save()
  return user
}

module.exports = mongoose.model('User', User);

Here is my root /users route and my /users/:id route.

userRoutes.route('/').get(function(req, res){
  User.find(function(err, users){
    if(err){
       res.status(400).send(err);
    } else {
       res.json(users)
    }
  });
});

userRoutes.route('/:id').get(function(req, res){
   User.findById(req.params.id, function(err, user){
     if(err){
       res.status(400).send(err)
     } else {
       if (user){
          res.status(200).json(user);
       } else {
          res.status(400).send('user not found :(')
       } 
    }
  });
});

And here is my add game route.

gameRoutes.route('/add').post( async function(req, res){
  try {
    var user = await User.findOne({ _id: req.body.owner })
    let game = new Game(req.body);
    if (!user){
      res.status(400).send('user not found.')
    } else {
      await game.save()
      await user.addGame(game._id);
      if (!game){
        res.status(400).send('game cannot be created');
      } else {
        res.status(200).json(game);
      }
    }
  } catch (error) {
    res.status(500).send(error);
  }
});

Finally, here is the data that is logged when I use mongoose.set('debug', true) and create a game.

 Mongoose: users.findOne({ _id: ObjectId("5daca0171febbb25f2c929dd") }, 
 { projection: {} })
 Mongoose: games.insertOne({ questions: [ { id: 0, qTitle: 'When is 
 Independence Day?', qAnswers: [ { aId: 0, aContent: 'July 18th' }, { 
 aId: 1, aContent: 'July 19th' }, { aId: 2, aContent: 'July 30th' }, { 
 aId: 3, aContent: 'July 4th' } ], answer: 3, correct: null }, { id: 1, 
 qTitle: 'When is Christmas Day?', qAnswers: [ { aId: 0, aContent: 
 'July 18th' }, { aId: 1, aContent: 'July 19th' }, { aId: 2, aContent: 
 'December 25th' }, { aId: 3, aContent: 'December 31st' } ], answer: 2, 
 correct: null } ], qTime: null, expDate: null, isPrivate: true, 
 isClosed: false, _id: ObjectId("5db5c2fe96960e318ae8f60f"), name: 
 'poppie', __v: 0 }, { session: null })
 Mongoose: users.updateOne({ _id: ObjectId("5daca0171febbb25f2c929dd"), 
 __v: 19 }, { '$set': { games: [ ObjectId("5db5c2fe96960e318ae8f60f") ] 
 }, 
 '$inc': { __v: 1 } }, { session: undefined })

Right after creating a game, if I go to /localhost:4000/users I see the resulting list of User's.

 [{
    "username": "matt_cee",
    "password": 
    "$2a$10$/ySrwkMxaHGO24FOEst3NuqpG4iQi78BUCSkl4Hb.RmjTIwynR3l.",
    "games": [
        "5db5c2fe96960e318ae8f60f"
    ]
  }]

As you can see, the games array contains the newly created game's id. I am able to log the updated User in the /add games route but when accessing the /:id user route, the returned User instance has an empty array for the games property.


Solution

  • I was able to figure out the issue was that I wasn't providing the property in the right format. Here is how my Game model was set up.

    let Game = new Schema({
        owner: { 
              id: { type: mongoose.Schema.Types.ObjectId,
                    ref: "User"
              },
              username: {type: String}
            }
        },
        name:{
            type: String
        },
        questions: {
            type: Array
        }
    });
    

    The problem was I was trying to update the User by adding the id of the newly created Game to user.games but the owner property wasn't populating properly because I was only passing the user's id not the username. Below is my updated game model.

    let Game = new Schema({
       owner: {
          type: mongoose.Schema.Types.ObjectId,
          ref: "User",
          required: true
       },
       name:{
          type: String
       },
       questions: {
          type: Array
       }
    

    })

    Special thanks to @user753642 with who's help I was able to better structure my code and debug the data.