Reputation: 217
I'm very confused about Population and Subdocuments with mongoose, can anyone help me understand the concepts behind it? Please feel free to post examples.
Don't be annoyed at me if i'm not clear, I'm new to express and mongodb but i'll try my best to explain what I'm trying to accomplish.
What I'm trying to do is create a new User and also create a list of tasks that belongs to this new User. When I save the new User it also saves an array of task inside tasks: []. So... I've created a User schema, Task schema, create view and user controller.
This is what I have and I'm lost at this point. Got the user name to save but tasks is empty.
What am I doing wrong?
models/User.js
var mongoose = require('mongoose'),
Task = require('./Task'),
Schema = mongoose.Schema;
var userSchema = new Schema({
name: {
type: String,
unique: true
},
tasks: [Task]
});
module.exports = mongoose.model('User', UserSchema);
models/Task.js
var mongoose = require('mongoose'),
User = require('./User'),
Schema = mongoose.Schema;
var TaskSchema = new Schema({
title : String,
description : String,
complete : Boolean,
userID : {
type : Schema.ObjectId,
ref : 'User'
}
});
module.exports = mongoose.model('Task', TaskSchema);
views/user/create.jade
block content
form(action='/user/save', method='POST')
input(type='text', name='title', id='title')
input(type='text', name='description', id='description')
input(type='checkbox', name='complete', id='complete')
button.btn(type='submit') Save
controllers/user/create.js
var User = require('../../models/User'),
Task = require('../../models/Task');
// CREATE
exports.get = function(req, res) {
res.render('user/create', {
title: 'Create User'
});
};
exports.post = function(req, res, next) {
var user = new User({
name: req.body.name,
title: req.body.title,
description: req.body.description,
complete: req.body.complete
});
User.findOne({name:req.body.name}, function(err, existing) {
if (err) {
return next(err);
}
user.save(function(err) {
if (err) {
return next(err);
}
res.redirect('/users');
});
});
};
controllers/user/edit.js
var User = require('../../models/User'),
Task = require('../../models/Task');
// EDIT
exports.get = function(req, res) {
User.findById(req.params.id, function(err, user) {
res.render('user/edit', {
user: user,
title: 'Edit User'
});
});
};
exports.post = function(req, res, next) {
User.findById(req.params.id, function(err, user) {
if (err) {
return next(err);
}
user.name = req.body.name || '';
user.title = req.body.title || '';
user.description = req.body.description || '';
user.complete = req.body.complete || '';
user.save(function(err) {
if (err) {
return next(err);
}
res.redirect('/users');
});
});
};
controllers/routes.js
var create = require('./user/create'),
edit = require('./user/edit');
exports = module.exports = function(app) {
// Users
app.get('/user/create', create.get);
app.post('/user/save', create.post);
app.get('/user/edit/:id', edit.get);
app.post('/user/update/:id', edit.post);
};
Upvotes: 0
Views: 114
Reputation: 8141
Three things:
First
Your schema defines Task as something nested within User, but your form and your routes are designed as though they were the same object. More specifically, this code:
user.name = req.body.name || '';
user.title = req.body.title || '';
user.description = req.body.description || '';
user.complete = req.body.complete || '';
user.save(function(err) {...
will only ever change the user's name because that's the only field you touch that matches your schema:
var userSchema = new Schema({
name: {
type: String,
unique: true
},
tasks: [Task]
});
If you want to add a new task for that user you would do it like this:
user.tasks.push({
title: req.body.title,
description: req.body.description,
complete: req.body.complete
})
user.save(function(err) {...
Second
Your routes are kind of goofy. For example, I would expect the route POST /user/update/:id
to accept only user properties, or tasks as an array. If I wanted a route to create individual tasks for a given user I would do it like this: POST /user/:id/task
and I would push tasks directly onto User.tasks with a mongo query like this:
// note that incoming data (req.params and req.body) should be validated by your controller, omitted here for brevity
User.update({_id: req.params.id}, {$push: {'tasks': req.body}}, function(err) {...})
Third
In mongoose there's a difference between a Schema (a document structure) and a Model (something that has its own mongodb collection that you can instantiate) I'm not sure you inteded to define Tasks as its own model. What you probably wanted is for Tasks to be nested within User.tasks, in which case you should do this:
var TaskSchema = new Schema({
title : String,
description : String,
complete : Boolean
});
var userSchema = new Schema({
name: {
type: String,
unique: true
},
tasks: [TaskSchema]
});
You don't have to nest tasks within users, the alternative would be defining them as separate collections in mongo and letting them reference each other, the way you have already with Task.userID
. But I would advise against mixing the two approaches together.
Upvotes: 2