mongoose's documentation example for population, gives an error - node.js

i had this problem in my own code. i copied the code from the example at Mongoose Query Population to see what am i doing wrong. but i have the same problem with their code too.
the problem is about the log in the exec callback:
console.log('The creator is %s', story._creator.name);
^
TypeError: Cannot read property '_creator' of null
and here is the code.
var mongoose = require('mongoose'),
Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
now using the models, making a new Person and saving it. and also saving a story and making the _creator of it to be equal to the id of the Person model, called aaron
var aaron = new Person({ _id: 0, name: 'Aaron', age: 100 });
aaron.save(function (err) {
if (err) return handleError(err);
var story1 = new Story({
title: "Once upon a timex.",
_creator: aaron._id // assign the _id from the person
});
story1.save(function (err) {
if (err) return handleError(err);
// thats it!
});
});
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});
UPDATE:
in database i have only one collection called poeple with only one document:
{
"_id": 0,
"name": "Aaron",
"age": 100,
"stories": [],
"__v": 0
}
the code does not have the world people in it so where the collection name comes from? i'm confused.
thanks for any help you are able to provide.

The story1 is saved until the callback function of it is called. Please try to move the Stroy.find into the callback function of story1.save as below.
story1.save(function (err) {
if (err) return handleError(err);
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});
});

Related

TypeError: Cannot read property 'push' of undefined - expressjs mongodb

I am trying to learn one to many relationship in MongoDB using mongoose and expressjs. I am trying to use reference method in which only id is stored as a reference.
User has already been created. Here is my code -
var mongoose = require("mongoose");
//saving application name in mongodb and connecting to it
mongoose.connect("mongodb://localhost/blog_demo_3");
//POST - title, content
var postSchema = mongoose.Schema({
title: String,
content: String
});
var Post = mongoose.model("Post", postSchema);
//USER - name email
var userSchema = mongoose.Schema({
email: String,
name: String,
//linking to many posts specific to user one to many relation
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post"
}
]
});
var User = mongoose.model("User", userSchema);
Post.create({
title: "How to cook burger pt 2",
content: "blah blah blah"
}, function(err, post){
User.find({name: "Bob Fischer"}, function(err, foundUser){
if(err)
console.log(err);
else {
//foundUser.posts.pus(post) - doesn't works
foundUser.posts.push(post._id);
foundUser.save(function(err, data){
if(err)
console.log(err)
else
console.log(data);
});
}
});
});
// User.create({
// email: "bob#foodtech.com",
// name: "Bob Fischer"
// }, function(err, createdBlog){
// if(err)
// console.log(err);
// else
// console.log(createdBlog);
// });
Please help. Thanks.
I'm sorry for not noticing such small syntax error.
User.find({name: "Bob Fischer"}, function(err, foundUser){
should be
User.findOne({name: "Bob Fischer"}, function(err, foundUser){

How to use object id that give reference in nodejs mongodb

There is no another error but I want to know just one thing.How to use that give reference in User schema object _id it means location_id how to use when I add new User.
User Schema :
var userSchema = Mongoose.Schema({
name:{type: String,require:true},
surname: {type: String,require:true},
tel: {type: String,require:true},
age: {type: String,require:true},
mevki_id: {type: String,require:true},
location_id: { type: Mongoose.Schema.Types.ObjectId, ref: 'locations' }
});
Location schema:
var LocationSchema = Mongoose.Schema ({
il: {type: String, require:true},
ilce: {type:String, require:true}
});
UserController -- I add user here
this.createUser = function(req, res) {
var la=new Location({il:'istanbul',ilce:'camlica',location_id:la._id}).save(function (err) {
if (err) return handleError(err);
});
var user = new User({
name:'akif',surname:'demirezen',tel:'544525',age:'45',mevki_id:'2',
}).save(function (err) {
if (err) return handleError(err);
res.send(JSON.stringify(job));
});
}
There are several errors in your code. For example, the require property should be required.
Other problem is that you are setting the location_id value of la with a reference to la, that at that time has not been yet assigned a value.
Mongo will automatically create a field called _id: ObjectId on all your objects. Try this:
this.createUser = function(req, res) {
var la = new Location({
il:'istanbul',
ilce:'camlica',
}).save(function (err, location) {
if (err) return handleError(err);
var user = new User({
name:'akif',
surname:'demirezen',
tel:'544525',
age:'45',
mevki_id:'2',
location_id: location._id
}).save(function (err, user) {
if (err) return handleError(err);
// Warning: AFAIK job does not exist, should it be user?
res.send(JSON.stringify(job));
});
});
}

Create an association through a single form Mongoose/express

Through a single form I'm trying to build a game object that consists of a 'game_name', and a 'game_length', and a ref association by ObjectId to a 'player'. What I have is building both objects but the player is not being saved in the players array in the Game model. Thanks for any help in advance.
Schema and Models
Game Schema/Model
var gameSchema = new mongoose.Schema({
course_name: String,
game_length: Number,
players: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Game'
}],
created: {type: Date, default: Date.now}
})
var Game = mongoose.model('Game', gameSchema);
Player Schema/Model
var playerSchema = new mongoose.Schema({
player_name: String,
})
var Player = mongoose.model('Player', playerSchema);
Post Route
app.post('/games', function(req, res){
Game.create(req.body.game, function(err, newGame){
if (err) console.log(err);
Player.create(req.body.player, function(err, newPlayer){
if (err) console.log(err);
newGame.players.push(newPlayer);
})
res.redirect('games');
})
})
It looks like you just need to call .save:
app.post('/games', function(req, res){
Game.create(req.body.game, function(err, newGame){
if (err) console.log(err);
Player.create(req.body.player, function(err, newPlayer){
if (err) console.log(err);
newGame.players.push(newPlayer);
newGame.save(function(err) {
if (err) return console.log(err);
// saved!
res.redirect('games');
});
})
})
})

Mongoose slice array, in populated field

I have the following mongoose schemas:
The main one is userSchema which contains an array of friends,
friendSchema. Each friendSchema is an object that contains an array of messageSchema. The messageSchema is the deepest object, containing the body of the message.
var messageSchema = new mongoose.Schema({
...
body: String
});
var conversationsSchema = new mongoose.Schema({
...
messages: [messageSchema]
});
var friendSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
conversation: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Conversation',
},
}, { _id : false });
var userSchema = new mongoose.Schema({
...
friends: [friendSchema]
});
When retrieving specific user's friend, I populate its friends profiles, and if a conversation exist, I populate the conversation too.
How can I slice conversations.messages array, which resides in the population of the conversationobject ? I don't want to return the whole messages.
var userId = req.userid;
var populateQuery = [{ path:'friends.user',
select: queries.overviewConversationFields },
{ path:'friends.conversation' }];
User
.find({ _id: userId }, { friends: 1 })
.populate(populateQuery)
.exec(function(err, result){
if (err) { next(err); }
console.log(result);
}
EDIT(1) : I tried
.slice('friends.conversation.messages', -3)
EDIT(2) : I tried in populate query
{ path:'friends.conversation', options: { 'friends.conversation.messages': { $slice: -2 } }
EDIT(3) : For now, I can achieve what I want, slicing the array after the query is executed. This isn't optimized at all.
A little workaround that works.
I didn't found how to $slice an array that resides in a populated field.
However, the $slice operator works perfecly on any array, as long as its parent document has'nt been populated.
1) I decided to update the conversationSchema by adding an array containing both user's Id involved in the conversation :
var conversationsSchema = new mongoose.Schema({
users: [type: mongoose.Schema.Types.ObjectId],
messages: [messageSchema]
});
2) Then, I can easily find every conversation my user participates to.
As I said, I can properly slice the messages array, because nothing has to be populated.
Conversation.find({ users: userId },
{ 'messages': { $slice: -1 }}, function(err, conversation) {
});
3) Finally all I have to do, is to query all friends and conversations separately, and put back everything together, with a simple loop and a _find.
That would do more or less the same procedure of a Mongo population
Using async.parallel for more efficiency :
async.parallel({
friends: function(done){
User
.find({ _id: userId }, { friends: 1 })
.populate(populateQuery)
.exec(function(err, result){
if (err) { return done(err);}
done(null, result[0].friends);
});
},
conversations: function(done){
Conversation.find({ users: userId }, { 'messages': { $slice: -1 }}, function(err, conversation) {
if (err) { return done(err); }
done(null, conversation)
});
}}, function(err, results) {
if (err) { return next(err); }
var friends = results.friends;
var conversations = results.conversations;
for (var i = 0; i < friends.length; i++) {
if (friends[i].conversation) {
friends[i].conversation = _.find(conversations, function(conv){
return conv._id.equals(new ObjectId(friends[i].conversation));
});
}
}
});
// Friends contains now every conversation, with the last sent message.

mongoose remove from nested documents

I have the following two schemas and models:
var Customer = new Schema({
name: String,
jobs: [{ type: Schema.Types.ObjectId, ref: 'Job' }]
});
var Job = new Schema({
title: String,
customer: { type: Schema.Types.ObjectId, ref: 'Customer' }
});
var CustomerModel = mongoose.model('Customer', Customer);
var JobModel = mongoose.model('Job', Job);
job documents have a reference to the customer document via _id, and the customer document also contains an array of all the jobs _id's.
When I delete a job I need to delete the corresponding _id from the Customer.jobs array.
Here is the route I have - the job gets deleted but I cannot remove it's id from the array
app.delete('/api/jobs/:jobId', function(req, res){
return JobModel.findById(req.params.jobId, function(err, job){
return job.remove(function(err){
if(!err){
CustomerModel.update({_id: job.customer._id}, {$pull : {'customer.jobs' : job.customer._id}}, function(err, numberAffected){
console.log(numberAffected);
if(!err){
return console.log('removed job id');
} else {
return console.log(err);
}
});
console.log('Job removed');
return res.send('');
} else{
console.log(err);
}
});
});
});
numberAffected is always 0 and 'removed job id' always get fired
You've got things backwards in your $pull. Try this instead:
CustomerModel.update({_id: job.customer}, {$pull : {jobs : job._id}}, ...

Resources