Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Databases

Killeon Patterson
Killeon Patterson
18,528 Points

Adding Data to MongoDB

Hello, I'm attempting to add data to the nested array of a mongo document. My 'UserSchema' is holding the array for my ProductSchema. Using a post route from the /profile URL I want to add product information to the ProductSchema and index the document. I'm having issues getting the data into the database. I receive a "cannot read property "products" of undefined. From what I see, I did define users and products. Below are my models and the route I'm attempting to use. Thank you.

var mongoose = require('mongoose');
var bcrypt = require('bcrypt');


//ProductSchema
var ProductSchema = new mongoose.Schema({
        title: {
          type: String,
          required: true
        },

        cost: {
          type: Number,
          required: true
        },

        createdAt: {type: Date, default: Date.now},
        updatedAt: {type: Date, default: Date.now},
       location: {
          type: Number,
          required: true
        },
        description: {
          type: String,
          required: true
         }
       });

       ProductSchema.method("update", function(updates, callback) {
         Object.assign(this, updates, {updatedAt: new Date()});
         this.parent().save(callback);
       });


//User Schema
var UserSchema = new mongoose.Schema({
    email: {
      type: String,
      unique: true,
      required: true,
      trim: true
    },
    name: {
      type: String,
      required: true,
      trim: true
    },
    organization: {
      type: String,
      required: true,
      trim: true
    },

    password: {
      type: String,
      required: true
    },

    product: [productSchema]
});
// authenticate input against database documents
UserSchema.statics.authenticate = function(email, password, callback) {
  User.findOne({ email: email })
      .exec(function (error, user) {
        if (error) {
          return callback(error);
        } else if (!user) {
          var err = new Error('User not found.');
          err.status = 401;
          return callback(err);
        }
        bcrypt.compare(password, user.password, function (error, result) {
          if (result === true) {
            return callback(null, user);
          } else {
            return callback();
        }
      })
    });
  }
// hash password before saving to database
UserSchema.pre('save', function(next) {
  var user = this;
  bcrypt.hash(user.password, 10, function(err, hash) {
    if (err) {
      return next(err);
    }
    user.password = hash;
    next();

})
  });

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

// Creating product orders
router.post('/profile', function(req, res, next) {
     User.find({}, null, function(err, users){
      if (err){
        var err = new Error("Man");
        next(err);
      } else {
          users.products.push(req.body.title, req.body.cost, req.body.location, req.body.description);
          users.save(function(err) {
          if (err){
            next(err);
          }
          return res.redirect('/about');
        })
        };
      });
      });
Adomas Domeika
Adomas Domeika
6,151 Points

Haven't yet reached the MongoDB course, but I think it is because you are sending cost - with the lowercase c, while your model has uppercase c - Cost (ProductSchema)

To be more precise, you are posting cost, but it doesn’t exist in your database. So you should either post Cost or rename it in your database to be cost with the lower case c.

8 Answers

Killeon Patterson
Killeon Patterson
18,528 Points

Thank you, Adomas. That edit didn't solve the issue, but I appreciate you pointing that out. It did help.

Ken Alger
STAFF
Ken Alger
Treehouse Teacher

Killeon;

Is there more to your project code somewhere? I get additional errors when I try to run the above code, such as router being undefined.

Post back with additional information please and we'll see if we can't get you sorted out.

Thanks,
Ken

Killeon Patterson
Killeon Patterson
18,528 Points

Hello Ken,

Thank you for replying. This is a link to my gist https://gist.github.com/Satellite9/6d81bb73e2a45f45fa58392910c79255. I ran the project again, I'm not receiving any additional errors. I appreciate you taking a look.

Thanks, Killeon

Ken Alger
Ken Alger
Treehouse Teacher

Killeon;

Is there a middleware file that is missing from that gist? When I run what is currently posted I get a Cannot find module '../middleware' error.

Post back with further information or to let me know that I'm crazy and am not seeing something on my end. ;-)

Ken

Killeon Patterson
Killeon Patterson
18,528 Points

Ken;

(not crazy) There is a "middleware" folder that is holding the "oindex.js". In my actual project, "oindex" is "index.js." I changed the name on github because it wouldn't let me save duplicate names.

If you're still having trouble running the project, I can try to push the complete project from my console into github. I attempted that yesterday, but I had issues. I'm not super familiar with those actions. Thanks.

Killeon

Ken Alger
Ken Alger
Treehouse Teacher

If you could get your project up onto GitHub, that would be very helpful. I'm kind of moving things around "blindly" with the hopes that where I get things to be is where and how you have things set up.

A README.md file would also be useful in explaining the project, how to run it, other things to consider, etc. Also noting which versions of the various pieces of the puzzle you're using would be great, e.g. Node and MongoDB.

Running your application did generate a market database with sessions and users collections on my end. Post back with further info and code and I'll continue to work on it. Also, if you could provide a more detailed error stack trace than "cannot read property "products" of undefined, that would likely be helpful as well.

Ken

Killeon Patterson
Killeon Patterson
18,528 Points

Hi Ken,

Here is the link to my GitHub repository https://github.com/Satellite9/MTMARKET. stack trace ---

events.js:183
          throw er; // Unhandled 'error' event
          ^
TypeError: Cannot read property '$push' of undefined
        at C:\mtmarket\index.js:27:26
        at C:\mtmarket\node_modules\mongoose\lib\model.js:4233:16
        at process.nextTick (C:\mtmarket\node_modules\mongoose\lib\services\query\completeMany.js:35:39)
        at _combinedTickCallback (internal/process/next_tick.js:131:7)
        at process._tickCallback     (internal/process/next_tick.js:180:9)
[nodemon] app crashed - waiting for file changes before starting...

On my end, I'm able to create the user profiles and retrieve them when I sign in. The app crashes when I attempt to add a product. I thought it may be how I added the Schema, but it looks fine. I'm using the "push" method in this iteration, but I was previously using the dot notion/save parent model method. The dot notation/save parent model did not crash the app and it did not save the new document either.

Ken, thank you for your time. Talk to you soon.

Best, Killeon

Ken Alger
Ken Alger
Treehouse Teacher

Killeon;

Check out the repository here and see if the changes make sense. It is working on my system and is saving to a products collection.

Some refactoring could/should be redone at this point inside the models/user.js file with the products schema in there, but I think you'll be able to see where this is headed.

Post back with any further questions.

Happy coding,
Ken W. Alger
@kenwalger

Killeon Patterson
Killeon Patterson
18,528 Points

Ken;

I see where we made the response into an object and saved it to the model. I also saw that I did not originally create an individual model for the productSchema, so I need to export and import that (I thought since it was inside of the Userschema that it only required that model). Although I don't see what changes need to be made to the user.js.

GitHub new commits https://github.com/Satellite9/MTMARKET I required the file ../models/product.js. I got a stack trace--

C:\mtmarktet\models\user.js:30 products: [productSchema] ^ ReferenceError: productSchema is not defined at Object.<anonymous> (C:\mtmarket\models\user.js:30:16) at Module._compile (module.js:652:30) at Object.Module._extension..js (module.js:663:10) at Module.load (module.js.505:32) at tryModuleLoad (module.js:505:12) at Function.Module._load (module.js:497:3) at Module.require (module.js:596:17) at require (internal/module.js:11:18) at Object.<anonymous> (C:\mtmarket\routes\index.js:3:12) at Module._compile (module.js:652:30) at Object.Module._extension..js (module.js:663:10) at Module.load (module.js:565:32) at tryModuleLoad (module.js:505:12) at Function.Module._load (module.js.497:3) at Module.require (module.js:596:17) at require (internal/module.js:11:18)

the syntax should be products: [productSchema], right?

Ken Alger
Ken Alger
Treehouse Teacher

Killeon;

You're getting that error because when you refactored productSchema out of user.js it broke the association on line 30 with products:[productSchema]. Take another look at the syntax on line 30 and how it should be referencing the new Product model.

Were you able to get things to work correctly with the code I posted on GitHub? I noticed that you had a few differences in routes/index.js as well.

Ken

Killeon Patterson
Killeon Patterson
18,528 Points

Ken;

No, I was not able to get it to work correctly. On one of my commits I tried 'products: [Product]' because that is the name of the variable holding the module to reference the schema? I looked at your routes/index.js commit (it appears to be currently removed from the project https://github.com/Satellite9/MTMARKET ) the only difference I was able to see was the bracket closing to the route handler? I got a syntax error when I ended it the same as the commit.

current stack trace-- C:\mtmarket\node_modules\mongoose\lib\schema.js:633 throw new TypeError('Undefined type ' + name + ' at array `' + path +) ^

TypeError: Undefined type 'model' at array 'products' at Function.Schema.interpretAsType (C:\mtmarket\node_modules\mongoose\lib\schema.js:633:15) at Schema.path (C:\mtmartket\node_modules\mongoose\lib\schema.js:508:29) at Schema.add (C:\mtmartket\node_modules\mongoose\lib\schema.js:378:12) at new Schema (C:\mtmartket\node_modules\mongoose\lib\schema.js:93:10) at Object.Module<anonymous> (C:\mtmartket\models\user.js:7:18) at Module.load (module.js:565:32) at tryModuleLoad (module.js:505:12) at Function.Module._load (module.js:497:3) at Module.require (module.js:596:17) at require (internal/module.js:11:18) at Object.<anonymous> (C:\mtmarket\routes\index.js:3:12) at Module._compile (module.js:652:30) at Object.Module._extensions..js (module.js:663:10) at Module.load (module.js:565:32)

Killeon

James Churchill
STAFF
James Churchill
Treehouse Teacher

Killeon,

Hi there! I grabbed the latest code from your repo (https://github.com/Satellite9/MTMARKET) and was able to reproduce your last reported error.

TypeError: Undefined type 'model' at array 'products'

To resolve this error, I updated the User schema in the models/user.js file so that the Product schema is referenced, not the model itself.

var UserSchema = new mongoose.Schema({
    email: {
      type: String,
      unique: true,
      required: true,
      trim: true
    },
    name: {
      type: String,
      required: true,
      trim: true
    },
    organization: {
      type: String,
      required: true,
      trim: true
    },
    password: {
      type: String,
      required: true
    },
    products: [Product.schema]
});

Notice the change from products: [Product] to products: [Product.schema]. When defining subdocuments in a Mongoose schema, you need to reference the schema, not the model.

After resolving that issue, I discovered additional errors in the "/profile" POST route handler. Here's the what I change that route handler's code to:

router.post('/profile', mid.requiresLogin, function(req, res, next) {
     User.findById(req.session.userId, function(err, user){
      if (err){
        var err = new Error("Man");
        next(err);
      } else {
        user.products.push({ title: req.body.title, cost: req.body.cost, location: req.body.location, description: req.body.description });
        user.save(function(err) {
          if (err){
            next(err);
          }
          return res.redirect('/about');
        })
      };
    });
  });

Here's a rundown of the changes that I made:

1) I added the mid.requiresLogin middleware in order to require that the user be logged into the site in order to accesss this route.

2) I switched to using the Mongoose model findById() method in order to retrieve a single User model instance. Previously, the find() method was returning an array of records, and your code wasn't taking that into account.

3) Now that we are expecting a single user to be returned by the query method, I renamed the users variable to user.

4) I updated the User model save() method call to this:

user.products.push({ title: req.body.title, cost: req.body.cost, location: req.body.location, description: req.body.description });

Notice that I'm creating a proper object literal for the Product object that's being pushed onto the products array.

5) I removed the following code as it's no longer needed:

const product = new Product({
    title: req.body.title,
    cost: req.body.cost,
    location: req.body.location,
    description: req.body.description
});

    product.save().then(data => {
        res.send(data);
    }).catch(err => {
        res.status(500).send({
      message: err.message || 'An error occurred while creating the product.'
  });
});

After making those changes, I was able to use the "/profile" page to add a product to my user record.

I hope this helps!

Thanks ~James

Killeon Patterson
Killeon Patterson
18,528 Points

James,

I appreciate your time and effort in looking over my project. Thank you for your time.

Killeon