14

I am trying to update a schema to add a new property field. I was hoping it would be as simple as adding the property to the schema with the updated field being accessible.

I have an existing schema

  let userDrinkSchema = new mongoose.Schema({  new Schema
    creator : { 
        type: mongoose.Schema.Types.ObjectId, 
        ref: 'user'  // name of user file
    },
    caffeine: Number,
    mgFloz: Number,
    name: String,
    size: Number,
    updated_at: {
        type: Date,
        default: Date.now()
    }
});

I need to add the id from this schema

const UserSchema = mongoose.Schema({

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

I am not sure how to add this property for each user. I followed this example Dealing with schema changes in Mongoose

The schema is now:

let DrinkSchema = new mongoose.Schema({
    user: { 
        type: mongoose.Schema.Types.ObjectId, 
        ref: 'user',
        required: true,
        default: null
    },
    caffeine: Number,
    mgFloz: Number,
    name: String,
    size: Number,
    imageUrl: String,
    date: {
        type: Date,
        default: Date.now()
    }
},
{
    collection: 'drinkList'
});

Unfortunately for me the user is null as well

{
 "_id":"58bba13bb7afeaa3180aa929",
 "caffeine":422,"mgFloz":218.7,
 "name":"10 Hour Energy Shot",
 "size":1.93,
 "url":"/caffeine-content/10-hour-eternal-shot",
 "date":"2017-03-28T13:10:12.650Z",
 "user":null
}

Is there a way to update the user field to get the user information? The schema that I am referencing is set up as

const SelectedDrinks = require('./userDrinks').schema;
const UserSchema = mongoose.Schema({
    name: {
        type: String
    },
    email: {
        type: String,
        required: true
    },
    username: {
        type: String, 
        required: true
    },
    password: {
        type: String,
        required: true
    },
    caffeine_list: [SelectedDrinks]
})

I can see that mongodb adds an id to each user when they are created. this is what i am trying to access.

My backend route is configured in express. With postman I can get this to work becuase I have the user id. I am not sure how to get the correct user id inside of this route.

    router.post('/addDrink', (req, res, next) => {
    let newDrink = new UserDrinks({
        creator: req.body.creator, // need id get user object id()
        caffeine: req.body.caffeine,
        mgFloz: req.body.mgFloz,
        name: req.body.name,
        size: req.body.size,
        updated_at: req.body.updated_at
    });

    newDrink.save( (err) => {
        if(err) {
            res.send(err);
        } else {
            User.findOne({ _id: newDrink.creator},  (err, user) => {
                user.caffeine_list.addToSet(newDrink)
                user.save( function (err) {
                    if(err) {
                        console.log(err);
                    }else {
                        res.status(201).json(newDrink);
                    }
                })
            })

        }

    })
});
Community
  • 1
  • 1
Winnemucca
  • 3,309
  • 11
  • 37
  • 66
  • Did you update the `drinkList` collection with the new data? – chridam Mar 28 '17 at 13:32
  • @chridam Essentially, I need to define the property in the collection first? like db.drinklist.update({}, {$set : {"user":" not sure here"}})? – Winnemucca Mar 28 '17 at 14:57
  • You need to update the document with the corresponding user's `ObjectId` value, I don't know the relationship – chridam Mar 28 '17 at 15:06
  • @chridam That is what I thought I was doing in user, but clearly not. I am updating my question to show the other collections. – Winnemucca Mar 28 '17 at 15:13
  • 1
    Are you looking to rename your field from `creator` to `user` in `drinklist` collection ? Something like `db.drinklist.updateMany( {}, { $rename: { "creator": "user" } } )` ?? You can then access the `user` with the new schema. – s7vr Apr 14 '17 at 14:49
  • I didn't think of that. Would it be best to set up the update in the route controller? I do not want to manually do this in the shell. – Winnemucca Apr 14 '17 at 15:11
  • You can expose it over route and pass the query, but this is one time thing right ? Something like `DrinkModel.update( { }, { $rename: { creator: 'user' } }, { multi: true }, function(err, data) { console.log(err, data); } );` – s7vr Apr 14 '17 at 15:22
  • If I expose it in a route it would just update the current user so it wouldn't be. I think a better approach would be to do the update over all of the user and work from there. – Winnemucca Apr 14 '17 at 15:29
  • yeah I think you should just use shell and rename it but if you really wanted to use mongoose then you should expose a separate route for just this part as you have already noted. – s7vr Apr 14 '17 at 16:01

1 Answers1

12

If I'm understanding this right, you're trying to replace the creator field with the user field. To accomplish this you'll need to do 2 things:

  1. Modify your /addDrink route
  2. Update any existing documents in the drinkList collection

1) When you create newDrink, set user instead of creator:

let newDrink = new UserDrinks({
    user: req.body.creator,
    caffeine: req.body.caffeine,
    mgFloz: req.body.mgFloz,
    name: req.body.name,
    size: req.body.size,
    updated_at: req.body.updated_at
});

2) Update all UserDrinks to rename the field:

UserDrinks.update({}, { $rename: { "creator" : "user" } }, { multi: true }, callback)

This will find all UserDrinks documents and rename the creator property to user.

A quick way to do this without having to create a new route for a one-time change is to create a temporary function for it under your express setup, run it locally, and delete/comment the code after so it doesn't run again. Ex:

function renameCreatorField() {
    UserDrinks.update({}, { $rename: { "creator" : "user" } }, { multi: true }, function(err, data) {
        if (!err) { 
            //success 
        }
    })
}

renameCreatorField();

This will run immediately when your server starts up. Once it runs once you can delete it because the changes we made in (1) will ensure any future UserDrinks documents have the correct field set.

Of course, if you're just looking for a quick fix and this isn't a live application you can just do (1), clear out your database, and start fresh with correct documents. But that's not the way to learn. :)

Kevin McGovern
  • 148
  • 2
  • 5
  • Hey man, thanks for the response. I had followed @Veeram and made updates in my mongo shell but the renameCreator function would have done the same. Stuck on req.body.creator is still null for me which is causing my error. Once I get this correct I am good to go. – Winnemucca Apr 23 '17 at 06:24
  • What does your request body look like? Both when you send it and when you print it out on your server. – Kevin McGovern Apr 24 '17 at 11:54