Mongoose populate return undefined - node.js

I'm currently trying to develop an app using mongo and node.js.
I am facing a problem when I want to build a query who use the populate option.
Here are my Schemas :
// Schema used by mongoose
var userSchema = new mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
login: String,
password: String,
movies: [ { type: mongoose.Schema.Types.ObjectId, ref: movieModel} ],
admin: Boolean
},{ collection: "user" });
var movieSchema = new mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
title: String,
}, { collection: "movie" });
As you can see, each user have an array of movies, this array contains valid ids of movies. What I want is to have the movies of an user. This is how I build my query :
var query = userModel.findOne({ login: req.session.user["login"] })
.populate("movies");
query.exec(function(err, user)
{
if (err)
throw err;
console.log(user.movies[0].title);
});
The query is executed successfully, but when I try to display the title of the first movie at the console.log line I got an error "TypeError: Cannot read property 'title' of undefined". I checked the documentation of mongoose and don't understand why I'm getting this error.
I would like to specify that my database contains valid data.
I put mongoose in debug mode, and this is the query that is executed :
Mongoose: user.findOne({ login: 'user' }) { fields: undefined }
Mongoose: user.find({ _id: { '$in': [ ObjectId("52e2a28949ad409834473e71"), ObjectId("52e2a28949ad409834473e79") ] } }) { fields: undefined }
The two ids on the second line are valid ids of movies. I would like to display their name.
Thanks a lot for your help.

What is the value of this: ref: movieModel?
movieModel would need to be set to the string like "Movie". See here for more information. It will need to match the identifier provided when you create the Movie model.
var Movie = mongoose.model('Movie', movieSchema);
So, you might have in a schema:
var userSchema = mongoose.Schema({
name: String,
favorite_movies: { type: Schema.Types.ObjectId, ref: 'Movie' }
});
var User = mongoose.model('User', userSchema);
I've used the string Movie in both the Schema definition and when creating the Movie type. They need to be exactly the same.
MongooseJs uses the string name of the Model to determine where to fetch the documents from when using ref and populate.
In the debug output, you can see how Mongoose is actually querying the wrong collection, as I'd expect it to be using movies.find to find the relevant Movie documents.

Related

How do I prevent Schema fields from being inserted into subdocument?

I'm making a dating app in node js and vue, and everything works however I wish to exclude password from being inserted into subdocument upon creation of a conversation. Right now I know that i can say .select('-password') when using User.findOne() but it doesn't work, when adding the user schema as a subdoc to my Conversations schema, which has user_one and user_two, each referring to a User schema. I need the password field, so I can't ommit it when creating a schema. Right Now my code looks like this:
User.findOne({ _id: fromUserId }, (errUserOne, userOne) => {
User.findOne({ _id: toUserId }, (errUserTwo, userTwo) => {
conversation = new Conversation({
_id: mongoose.Types.ObjectId(),
user_one: userOne,
user_two: userTwo
});
conversation.save();
const message = new Message({
_id: mongoose.Types.ObjectId(),
conversation_id: conversation._id,
message: req.body.message,
user_id: fromUserId
});
message.save();
res.sendStatus(201);
});
});
However this code saves the password to the Conversation collection, which I don't want.
User.find({ _id: :{ $in : [fromUserId,toUserId] }, { password:0 } , (err, userArray) => {
//your code goes here
});
Two things, You are querying two time for getting users. You can merge it into single query and for excluding the password field you can pass {password:0}. Which will exclude it in the documents.
also while you define Conversation schema don't make user_one and user_two type of user. Instead define only whatever properties of user you want to save like:
var Conversation = new Schema({
_id : ObjectId,
user_one : {
_id: ObjectId,
//all other fields
},
user_two : {
_id: ObjectId,
//all other fields
},
});

node js, mongodb populate the populated

I've hit a wall in my server when I needed to get data from my server.
The following represents my schemas:
Schema one:{
name: String
}
Schema two:{
code:String,
name_id: refid: schema One
}
Schema three:{
phone:number
code:[refid: Schema two]
}
If I needed data from schema three, and the objects from object ids that are saved in the code array I would use populate and I would get the object referenced by object id.
Question is is it possible to populate the populated data?
If populate schema three
I would get objects such as:
{phone : 000911,
code: :{code:String,
name_id: refid: schema One}
in the previous example I want to populate the name id, is that possible?
With Mongoose, you can populate your schema with dot notation like this:
const One = new Schema({
name: String
})
const Two = new Schema({
code: String,
name: {
type: Schema.ObjectId,
ref: 'One'
}
})
const Three = new Schema({
phone: number
code: [{
type: Schema.ObjectId,
ref: 'Two'
}]
})
Three.find((err, three) => {
if (err) console.log(err)
console.log(three)
// => {
// phone : "the phone number from schema Three",
// code: {
// code: "the code from schema Two",
// name: "the name from schema One"
// }
// }
})
.populate('code.name')

Updating a Record in Mongo After Retrieving Its ID From Another Record

I am trying to make an API point that would do the following. I submit an Object ID in the path. The record with that ID is found. Then, the program looks into a certain field of this object. The field contains an ObjectID for another entry in the database. At last, I need to pull up that record and increment a certain field in it.
In short, I have a child->parent relationship between certain records and would like the ability of incrementing a certain field within the parent record by submitting the child's id to the API point.
Here is the code I had that did the basic child increment. How can I go about doing it for the parent?
router.get('/today/parent/up/:id', function(req, res){
var collection = db.get('Activity');
collection.update({
_id: req.params.id
},
{
$inc: {
"repetitions.today": 1,
"repetitions.total": 1
}
}, function(err, activity){
if (err) throw err;
res.json(activity);
});
})
First use mongo references, heres documenttion:
https://docs.mongodb.com/manual/reference/database-references/
here's mongoose documentation
http://mongoosejs.com/docs/2.7.x/docs/populate.html
Basically You need to do this:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var PersonSchema = new Schema({
name : String
, age : Number
, stories : [{ type: Schema.ObjectId, ref: 'Story' }]
});
var StorySchema = new Schema({
_creator : { type: Schema.ObjectId, ref: 'Person' }
, title : String
, fans : [{ type: Schema.ObjectId, ref: 'Person' }]
});
var Story = mongoose.model('Story', StorySchema);
var Person = mongoose.model('Person', PersonSchema);
Then you could use .populate() method, and then you could extract your populated model and make changes and save them with .save(), but remember to use it in populated model, not the parent one. For ex. You've got author which contains reference to books, so you make request
author.findOne({'name': 'King'}).populate('books').exec((err, king) => {
let book0 = king.books[0];
book0.title = 'I need to change this one';
book0.save((err, data) => {
console.log('saved referenced object')
}
})

Mongoose populate schema from different Database

For example i have SchemaA and SchemaB which both belong to different database. Inside SchemaA i have doc.b = {type: mongoose.Schema.Types.ObjectId, ref: 'SchemaB'}. When i am doing populate of this i got below error. MissingSchemaError: Schema hasn't been registered for model "SchemaB". Use mongoose.model(name, schema) From my research i have read that mongoose support population cross databases.
I am requiring mongoose multiple times for each schema, is that the problem?
Basically what i need is two different schema which is connecting to different databases to work together with populate. If i register schema on connection created by mongoose they will not be registered on the same list. If there a way to success that?
Basically what we need to do is pass schema to population, something like this:
User.findOne({
_id: req.user._id
}).populate({
path: 'roomsContainer',
model: RoomsContainer,
populate: [{
path: 'creator'
},{
path: 'users'
},{
path: 'rooms',
model: Room
}]
}).exec(function(err, user) {
// do some magic
});
Where User belong to database one and Room, RoomsContainer belong to database two.
const db1 = mongoose.createConnection('mongodb://localhost:27000/db1');
const db2 = mongoose.createConnection('mongodb://localhost:27001/db2');
const conversationSchema = new Schema({ numMessages: Number });
const Conversation = db2.model('Conversation', conversationSchema);
const eventSchema = new Schema({
name: String,
conversation: {
type: ObjectId,
ref: Conversation // `ref` is a **Model class**, not a string
}
});
const Event = db1.model('Event', eventSchema);
Refrence here

nodejs mongoose many-to-many relation on MongoDB

I'm trying to make a many-to-many relation between two documents in mongoose. Just can't make it work.
I've been trying to utilize the mongoose populate method, but with no success. Does anyone know any good tutorials or example on how to take on the matter?
Update:
Got schemas
var EventSchema = new Schema({
users: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
and
var UserSchema = new Schema({
events: [{
type: Schema.Types.ObjectId,
ref: 'Event'
}]
});
In my tests I pused to event model user like so
event.users.push(user);
event.save(function(err, doc) {
user.events[0].should.equal(event._id);
done();
});
firstly I need to push somehow saved event to added user to event. Then by using populate I should can 'dress up' every object in events array and users array. Preferably in post save callback, if I understood populate correctly.
This test pases
it('creates', function(done) {
event.users.append(user);
event.save(function(err, ev) {
user.save(function(err, doc) {
doc.events[0].should.equal(ev._id);
doc.populate('events', function(err, d) {
console.log(d);
done();
});
});
});
});
So I know the ids are stored correctly, but when I run doc.populate() the returned document has events array empty. Just don't get it.
Made it work... used mongo-relation package to add the needed ids for me, but docs for this plugin made me change the schema form
var UserSchema = new Schema({
events: [{
type: Schema.ObjectId,
ref: 'Event'
}]
});
to
var UserSchema = new Schema({
events: [Schema.ObjectId]
});
once corrected, it worked.

Resources