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 trialKilleon Patterson
18,528 PointsAdding 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');
})
};
});
});
8 Answers
Killeon Patterson
18,528 PointsThank you, Adomas. That edit didn't solve the issue, but I appreciate you pointing that out. It did help.
Ken Alger
Treehouse TeacherKilleon;
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
18,528 PointsHello 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
Treehouse TeacherKilleon;
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
18,528 PointsKen;
(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
Treehouse TeacherIf 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
18,528 PointsHi 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
Treehouse TeacherKilleon;
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
18,528 PointsKen;
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
Treehouse TeacherKilleon;
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
18,528 PointsKen;
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
Treehouse TeacherKilleon,
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
18,528 PointsJames,
I appreciate your time and effort in looking over my project. Thank you for your time.
Killeon
Adomas Domeika
6,151 PointsAdomas Domeika
6,151 PointsHaven'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.