Populate in Mongoose not working - node.js

I am trying to perform associations by referencing method. There are 2 models:
1. User
2. Product
I have established one-to-one relationship of 1 user can have multiple products. User creation is successful
Product creation is successful
Code Inputs
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/product_demo_x9");
Product Schema
var productSchema = new mongoose.Schema({
category : String,
Brand: String
});
var Product = mongoose.model("product", productSchema);
User Schema
var userSchema = new mongoose.Schema({
email: String,
name: String,
products: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Product"
}
]
});`
var User = mongoose.model("user", userSchema);
User Creation
User.create({
email: "madhur#google.com",
name: "Maddy"
},function(err,newUser){
if(err){
console.log(err);
}
else {
console.log(newUser);
}
});
Product Creation
Product.create({
category: "Smartwatches",
Brand: "Samsung and Google"
},
function(err,product){
console.log(product);
User.findOne({name : "Maddy"},function(err,foundUser){
if(err) {
console.log(err);
}
else {
foundUser.products.push(product);
foundUser.save(function(err,updatedUser){
if(err){
console.log(err);
}
else {
console.log(updatedUser);
}
});
}
});
});
Display of associated Data on the console
User.find({email: "madhur#google.com"}).
populate("products").
exec(function(err,user){
if(err){
console.log(err);
}
else {
console.log(user);
}
});
Code Outputs
User Creation (Success)
[{
products: [],
_id: 5a47acb0317d4e3c2081b8ce,
email: 'madhur#google.com',
name: 'Maddy',
__v: 0
}]
Product Creation and associating (Success)
{
_id: 5a47acd53c771123b4018ff1,
category: 'Smartwatches_2',
Brand: 'Samsung and Google',
__v: 0
}
{
products: [ 5a47acd53c771123b4018ff1 ],
_id: 5a47acb0317d4e3c2081b8ce,
email: 'madhur#google.com',
name: 'Maddy',
__v: 1
}
Display of embedded data using populate - Failure!!
{ MissingSchemaError: Schema hasn't been registered for model "products".
Use mongoose.model(name, schema)
at new MissingSchemaError
Can anyone please explain me how to do it correctly?
Thanks in Advance

Model Name is Case-sensitive
'Product' is not equal to 'product'
and when u create a model as 'product' (singular) it converts it into plural, i.e. 'products', this is default mongoose behavior, can be overridden.
so change the following:
var userSchema = new mongoose.Schema({
email: String,
name: String,
products: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "products" //<---- changed 'Product' to 'products'
}
]
});`
var User = mongoose.model("user", userSchema);

Try this
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/product_demo_x9');
var productSchema = new mongoose.Schema({
category: String,
Brand: String
});
var Product = mongoose.model('Product', productSchema);
var userSchema = new mongoose.Schema({
email: String,
name: String,
products: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Product'
}
]
});
var User = mongoose.model('User', userSchema);
User.create({
email: 'madhur#google.com',
name: 'Maddy'
}, function(err, newUser) {
if (err) {
console.log(err);
} else {
console.log(newUser);
}
});
Product.create({
category: 'Smartwatches',
Brand: 'Samsung and Google'
},
function(err, product) {
console.log(product);
User.findOne({name: 'Maddy'}, function(err, foundUser) {
if (err) {
console.log(err);
} else {
foundUser.products.push(product);
foundUser.save(function(err, updatedUser) {
if (err) {
console.log(err);
} else {
console.log(updatedUser);
}
});
}
});
});
User.find({email: 'madhur#google.com'})
.populate('products')
.exec(function(err, user) {
if (err) {
console.log(err);
} else {
console.log(user);
}
});

Solved
Did the following
Downgraded my Mongoose version from 5.00x to 4.10.8 using the following command npm remove mongoose then npm install mongoose#4.10.8 --save
Made the following change in app.js file
var userSchema = new mongoose.Schema({
email: String,
name: String,
products: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "product" //<---- changed 'Product' to 'product'
}
]
});`
var User = mongoose.model("user", userSchema);
Thanks to the Stack community for giving a try!

Related

Inserting an object into a list on a mongoDB collection

I have a collection created with the below schema
const userSchema = new mongoose.Schema({
Name: String,
email: String,
music: Array
});
var User = new mongoose.model("User", userSchema);
However, i am having issue inserting the object below into the music array
var newMusic = {
artist: "Rihanna",
title: "Believe It"
};
Below is the code i am running to insert the above into the music array
User.update({
_id: req.user._id
}, {
$push: {
music: newMusic
}
});
No error message, just not updating the document.
I finally figured it out. The below code works
User.update({
_id: req.user._id
}, {
$push: {
music: newMusic
}
}).then(data => {
console.log(data);
});

How to use mongoose to create a student that's managed by a parent

Edit #2: Working code
This does what I want it to do now:
// route
app.post("/users/:id/createStudent", function(req, res){
Student.create(function(err){
if(err){
console.log(err)
res.redirect("/")
} else {
const newStudent = new Student({
firstName: req.body.firstName,
lastName: req.body.lastName,
age: req.body.age,
instrument: req.body.instrument,
});
newStudent.save()
.then(() => Parent.findById(req.params.id))
.then((parent) => {
parent.students.push(newStudent);
return parent.save();
});
req.flash("success", "Successfully Created Student");
res.redirect("/users/:id");
}
})
});
// parent model
const mongoose = require("mongoose"),
Schema = mongoose.Schema,
passportLocalMongoose = require("passport-local-mongoose");
const ParentSchema= new Schema({
username: String,
lastName: String,
email: String,
password: String,
students: [],
});
ParentSchema.plugin(passportLocalMongoose);
const Parent = mongoose.model("parent", ParentSchema);
module.exports = Parent;
Brand new developer here. I'm trying to build an app where a parent user can create a student user and a teacher user can assign said student weekly tasks. I'm having trouble with the create student route. I'm not sure how to get the student object to store the parent's id properly. I've been trying to find a solution for a few days now and can't seem to find anything that deals with this specifically and the docs haven't helped either. I hope I'm just missing something and one of you kind folks can at least point me in the right direction.
Here's my code:
//parent model
const mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
const parentSchema= new mongoose.Schema({
username: String,
lastName: String,
email: String,
password: String,
student: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Student"
},
username: String,
}
});
parentSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("Parent", parentSchema);
// student model
const mongoose = require("mongoose");
const studentSchema = new mongoose.Schema({
firstName: String,
lastName: String,
age: String,
instrument: String,
parent: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Parent"
},
username: String
},
});
module.exports = mongoose.model("Student", studentSchema);
// create student route
app.post("/users/:id/createStudent", function(req, res){
const newStudent = new Student({
firstName: req.body.firstName,
lastName: req.body.lastName,
age: req.body.age,
instrument: req.body.instrument,
parent: {
_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Parent"
},
username: String
},
});
Parent.findById(req.params.id, function(err, foundParent){
if(err){
req.flash("error", "Something went wrong");
console.log(err);
res.redirect("/users/:id");
} else {
const parent = foundParent
Student.create(newStudent, parent, function(err, student){
if(err){
console.log(err);
} else {
student.parent.id = req.parent._id;
student.parent.username = req.parent.username;
student.save();
parent.student.push(newStudent);
parent.save();
req.flash("success", "Successfully Created Comment");
res.redirect("/users/" + parent._id);
}
})
}
});
});
In the mongo shell, db.students.find() puts out this as my student object after I fill out the form:
db.students.find()
{ "_id" : ObjectId("5f0b33facd6fa70355f14774"), "firstName" : "Johnny", "lastName" : "Apple", "age" : "2014-03-04", "instrument" : "drums", "parent" : { "username" : "function String() { [native code] }" }, "__v" : 0 }
Sorry for the long code. I've just been trying so many things that it's added up to what you see here. Thanks for any advice you might give and for reading this far.
Edit
Updated code:
app.post("/users/:id/createStudent", function(req, res){
Parent.findById(req.params.id, function(err, foundParent){
if(err){
req.flash("error", "Something went wrong");
console.log(err);
res.redirect("/users/:id");
} else {
const newStudent = new Student({
firstName: req.body.firstName,
lastName: req.body.lastName,
age: req.body.age,
instrument: req.body.instrument,
parent: {
id: foundParent,
username: foundParent.username
},
});
Student.create(newStudent, foundParent, function(err, student){
if(err){
console.log(err);
} else {
student.parent._id = foundParent._id;
student.parent.username = foundParent.username;
student.save();
foundParent.student.push(newStudent);
foundParent.save();
req.flash("success", "Successfully Created Student");
res.redirect("/users/" + foundParent._id);
}
})
}
});
});
So the new error this is producing is DocumentNotFoundError: No document found for query "{ _id: 5f0a7026e330500413ee599a }" on model "Student" which I assume is because I don't have populate in there. I'm just not sure where the populate option would fit in?
mongoose.Schema.Types.ObjectId is a type not a value.
Try using mongoose.Schema.Types.ObjectId(req.parent.id)
Edit
Another option to try:
Move the const newStudent = block inside the else block of the findById callback.
Inside the new Student( constructor, use
parent: {
id: foundParent,
username: foundParent.username
}
Because of the schema definition, when you save the document, mongoose should store a DBRef in the student collection, which can then be reconstituted with populate.

Reference not populated

In a User schema, I have a simple reference to a Customer schema.
const UserSchema = new Schema({
customer: { type: Schema.Types.ObjectId, ref: Customer }, // Customer is the compiled CustomerSchema
...
});
const CustomerSchema = new Schema({
name: String,
...
});
In an Express controller, I'm fetching an user and I'm trying to embed the customer in the returned JSON:
export function me(req, res, next) {
User
.findOne({ _id: req.user._id }, '-salt -hashedPassword')
.populate('customer')
.exec((err, user) => {
if(err) return next(err);
if(!user) return res.json(401);
res.json(user);
});
}
But in the response, customer is null.
The test data I use:
A user document:
{
"_id" : ObjectId("570d1f0938f7da5151b815d2"),
"customer" : ObjectId("570d1f0838f7da5151b815d0"),
...
}
The related customer document:
{
"_id" : ObjectId("570d1f0838f7da5151b815d0"),
...
}
Probably a noob question, but I don't see what I don't see what I could forget =)
I think ref must be a string:
customer: { type: Schema.Types.ObjectId, ref: 'Customer' },

Mongoose objectId is not saving in another collection

I am new to mongoose and nodejs. Please help me to understand what is wrong in my code while saving collection. My user.js looks like below
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt-nodejs');
var UserSchema = new Schema ({
name: { type: String, required: true },
username:{ type:String, required: true, index:{ unique: true}},
password:{ type: String, required: true, select: false},
email:{ type: String, required: true, select: true},
mobile:{ type: String, required: true, select: true},
nativecid:{ type: Schema.Types.ObjectId, ref:'City'},
regdate:{ type: Date, default: Date.now },
did:{ type: String, required: false }
});
UserSchema.pre('save', function(next){
var user = this;
if(!user.isModified('password')) return next();
bcrypt.hash(user.password, null, null, function(err, hash){
if(err) return next(err);
user.password = hash;
next();
});
});
UserSchema.methods.comparePassword = function(password){
var user = this;
return bcrypt.compareSync(password, user.password);
};
module.exports = mongoose.model('User', UserSchema);
And my City model ie city.js looks like below
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CitySchema = new Schema({
name: { type: String, required: true },
status: { type: Boolean, default: true },
date: { type: Date, default: Date.now }
});
module.exports = mongoose.model( 'City', CitySchema );
City is already stored in database as below
{ "_id" : ObjectId("56a4a0adb0f445561cfd4e37"), "name" : "New York", "date" : ISODate("2016-01-24T10:00:13.220Z"), "status" : 1, "__v" : 0 }
I want this ObjectId of New York should be saved in user collection while user signups. I am trying like below but not succeed.
var User = require('../models/user');
var City = require('../models/city');
api.post('/signup', function(req, res){
var user = new User({
name: req.body.name,
username: req.body.username,
password: req.body.password,
email: req.body.email,
mobile: req.body.mobile
});
City
.findOne({ name: "New York" })
.populate('_id')
.exec(function (err, city1) {
if(err){
res.send(err);
return;
}
console.log('The creator is %s', city1.name);
return user.nativecid = city1._id;
})
user.save(function(err){
if(err){
res.send(err);
return;
}
res.json({
success: true,
message: 'User created successfully!'
});
});
});
I am not understanding what is wrong. Please advice me.
Just save user in city.findOne (nested) and may be no need to populate you should use projection.
City.findOne({ name: "New York" }, {name:1}) // ID return defaulat
.exec(function (err, city1) {
if(err){
res.send(err);
return;
}
console.log('The creator is %s', city1.name);
user.nativecid = city1._id;
user.save(function(err1){
if(err1){
res.send(err1);
return;
}
res.json({
success: true,
message: 'User created successfully!'
});
});
})

Mongoose findOneAndUpdate nested documents

I'm trying to update a document which contains 2 other documents. To achieve this task, I use findOneAndUpdate, but mongoose throws me a CastError (Cast to ObjectId failed).
My models:
user.js
var userSchema = new Schema({
email: String,
info: {
type : Schema.ObjectId,
required : true,
ref : 'Info'
}
});
module.exports = mongoose.model('User', userSchema);
info.js
var infoSchema = new Schema({
firstname: String,
lastname: String
});
module.exports = mongoose.model('Info', infoSchema);
My query:
var tmp = {
email: req.body.email,
info: {
name: req.body.info.name
}
};
User.findOneAndUpdate({
_id: req.params.id
}, tmp, {
upsert: false,
new: true
}).exec(function(err, doc) {
/* check errors */
/* send response */
});
What am I doing wrong? Are my models poorly set?
CastError: Cast to ObjectId failed
The type of info is Schema.ObjectId, whereas one object
info: {
name: req.body.info.name
}
is passed into it as ObjectId, as result, it failed.
Here maybe one work around.
var new_info = new Info({
firstname: req.body.info.name.firstname, //
lastname: req.body.info.name.lastname //
});
new_info.save(function(err, doc) {
if (err)
console.log(err);
else {
var tmp = {
email: req.body.email,
info: doc._id
}
User.findOneAndUpdate({
_id: req.params.id
}, tmp, {
upsert: false,
new: true
}).exec(function(err, doc) {
//
});
}
});

Resources