Mongoose findByIdAndUpdate - node.js

I trying to edit and update a form using mongoose. The code seems fine to me, but it doesn't work. I have tried so many ways but the updated version is still the same, I uses a put route to send the form, when I output req.body.studentInfo to the console, it is correct, but the update remains the same. Please help
This is my schema
var mongoose = require("mongoose");
var uniqueValidator = require('mongoose-unique-validator');
var passportLocalMongoose = require("passport-local-mongoose");
var mongoose = require("mongoose");
var UserSchema = new mongoose.Schema({
studentInfo: {
first_name: String,
middle_name: String,
last_name: String,
street: String,
town: String,
city: String,
region: String,
country: String,
studentId: String,
day: Number,
month: String,
year: Number,
},
username: {type: String, required:true, unique:true},
passport: String
});
UserSchema.plugin(uniqueValidator);
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("StudentInfo", UserSchema);
This is my App.js
app.put('/:id', function(req,res){
StudentInfo.findByIdAndUpdate(req.params.id, {$set: req.body.studentInfo}, function(err, updated){
console.log(req.params.id);
console.log(req.body.studentInfo);
if(err) {
console.log(err);
}
else {
res.redirect('/' + req.params.id);
}
});
});
The studentInfo is an object that contains the names of each variables in my form which I name was studentInfo[name of variable]. Please help

It should be specified that mongoose should return the updated document - by default it returns the original (this is also the behavior of mongodb). I think that if the code gets changed to this:
StudentInfo.findByIdAndUpdate(req.params.id, {$set: req.body.studentInfo}, { new: true }, function(err, updated){
...
});
you will receive the updated document in the callback.

As #Denny mentioned in his answer, mongoose will not return the updated document in the callback until you pass {new : true } option.
For Details and available options check findByIdAndUpdate Docs

Related

Error when using _id as a property type in a Mongoose Schema

I am learning MongoDB and mongoose at the moment. I have a Archive and a User schema in mongoose:
archive.js
var mongoose = require('mongoose');
var User = require('../users/user');
var notesSchema = new mongoose.Schema({
author: User.userId,
text: String,
files:[String]
});
var archiveSchema = new mongoose.Schema({
name: String,
priority: String,
deadline: Date,
status: String,
assigned_memnbers: [User.userId],
notes: [notesSchema],
});
archiveSchema.virtual('archiveId').get(function() {
return this._id;
});
module.exports = mongoose.model('Archive', archiveSchema);
user.js:
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
username: String,
mail: String,
bio: String,
password: String
});
userSchema.virtual('userId').get(function() {
return this._id;
});
module.exports = mongoose.model('User', userSchema);
When I run my server i get the error
TypeError: Invalid value for schema path `author`, got value "undefined"
The the problem comes from author: User.userId, but I don't know how to make a reference between the two tables.
For reference, here is what my complete db design more or less looks like:
Any input on how to solve this problem or improve the overall design is welcome. Thanks you.
I think what you're talking about is a reference to other collection:
author: { type: Schema.Types.ObjectId, ref: 'User' }
and
assigned_members: [{ type: Schema.Types.ObjectId, ref: 'User' }]
should work fine.
Source: Mongoose population
I faced the same issue.I had imported a module, It was just not exporting from another module. so I have added:
exports.genreSchema = genreSchema;

Mongoose pre-save hook fires, but does not persist data

I am encountering a problem where my Mongoose pre.save() hook is firing, but the attribute does not get saved to the database. I have been searching for a long time without finding an answer.I found this thread, and the behaviour I am experiencing is very similiar, but OP's problem is related to the context of this, whereas I seem to have a different problem.
Here is my models.js:
'use strict';
const mongoose = require("mongoose");
const slugify = require("slugify");
let Schema = mongoose.Schema;
let BlogPostSchema = new Schema({
title: {
type: String,
required: true
},
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
author: String,
post: {
type: String,
required: true
}
});
BlogPostSchema.pre('save', function(next) {
this.slug = slugify(this.title);
console.log(this.slug);
next();
});
// Passed to templates to generate url with slug.
BlogPostSchema.virtual("url").get(function() {
console.log(this.slug);
console.log(this.id);
return this.slug + "/" + this.id;
});
BlogPostSchema.set("toObject", {getters: true});
let BlogPost = mongoose.model("BlogPost", BlogPostSchema);
module.exports.BlogPost = BlogPost;
And here is the relevant lines in the router file index.js:
const express = require('express');
const router = express.Router();
const BlogPost = require("../models").BlogPost;
// Route for accepting new blog post
router.post("/new-blog-post", (req, res, next) => {
let blogPost = new BlogPost(req.body);
blogPost.save((err, blogPost) => {
if(err) return next(err);
res.status(201);
res.json(blogPost);
});
});
I am able to save the blog post to the database, and my console.log's correctly prints out the slug to the console. However, the this.slug in the pre-save hook does not get persisted in the database.
Can anybody see what the problem is here? Thank you so much in advance.
Mongoose will act according to the schema you defined.
Currently, your schema does not contain s filed named slug.
You should add a slug field to your schema.
Changing your current schema to something like this should work:
let BlogPostSchema = new Schema({
slug: String,
title: {
type: String,
required: true
},
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
author: String,
post: {
type: String,
required: true
}
});

Retrieve Array in Subdocument MongoDB

I have a Users model structure somewhat like this:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [models.Do.schema],
}
And the child "Do" schema somewhat like this (in a different file):
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
And I'm trying to figure out how to retrieve the todosDo array for the signed in user. This is what I've got so far:
// Get all "Do" todos from DB
// Experimenting to find todos from certain user
User.findById(req.user.id, function(err, user){
if(err){
console.log(err);
} else {
doTodos = user.todosDo, // this obviously doesn't work, just an idea of what I was going for
console.log(doTodos);
finished();
}
});
Am I referencing the child/parent wrong or am I just not retrieving the array right? Any help is greatly appreciated!
As far I guess you may want to edit as raw js objects so you need to use lean() function. without using lean() function user is mongoose object so you can't modify it.
can try this one:
User.findById(req.user.id)
.lean()
.exec(function (err, user) {
if(err){
console.log(err);
return res.status(400).send({msg:'Error occurred'});
}
if(!user) {
return res.status(400).send({msg:'User Not found'});
}
doTodos = user.todosDo;
console.log(user.todosDo); // check original todos
console.log(doTodos);
return res.status(200).send({doTodos : doTodos }); // return doTodos
});
and to refer child schema in parent schema from different model you can access a Model's schema via its schema property.
say in doSchema.js file
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
module.exports = mongoose.model( 'DoSchema', doSchema );
in user.js file
var DoModel = require('./doSchema');// exact path
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [DoModel.schema],
}
Thanks for your help everybody! My problem was that I needed to push all the newly created todos in the post route to todosDo, so then I could retrieve them at the get route. Everything's working now!

Express: Embed document in the existing document

I am developing an application in Express, Node and Mongo being the database. I have a collection users, and user can have mutiple registered-IDs. It like a one-to-many relationship. I m trying to embed a document in the user collection like this:
post(function (req, res, next) {
var pid=req.body.pid;
var sid=req.body.sid;
var rfname=req.body.rfname;
var des=req.body.des;
var brand=req.body.brand;
var model=req.body.model;
var serial=req.body.serial;
var location=req.body.location;
var arr={pid: 'pid', sid: 'sid', rfname: 'rfname' ,des: 'des', brand: 'brand', model: 'model' ,serial: 'serial', location: 'location'};
mongoose.model('User').findOne({'pemail': req.session.email}, function (err, user){
if(err){
} else {
user.registeredId = arr;
user.save(function(err){
if(err){
} else {
res.render('user/register', {'success': 'dfhlaksdhfh'});
}
})
}
});
}
My user schema is like this:
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
email: String,
password: String,
fname: String,
lname: String,
plang: String,
slang: String,
country: String,
state: String,
city: String,
postalcode: String,
address1: String,
address2: String,
pemail: String,
semail: String,
age: String,
gender: String,
pphone: String,
sphone: String,
q1: String,
a1: String,
q2: String,
a2: String,
cfname: String,
clname: String,
cemail: String
});
mongoose.model('User', userSchema);
Guide me, what am i doing wrong, because it does not embed document in the existing document. Do I need to define that in schema, if so, then how?
In your schema definition, the field registeredId is not defined and by default through the strict option, Mongoose ensures that values passed to your model constructor that were not specified in our schema do not get saved to the db, hence it is not creating the modified document.
You can either explicitly define the field in your schema or set the strict option to false in your schema definition:
// set to false..
var userSchema = new Schema({..}, { strict: false });
and then implement one of the findAndModify() methods like findOneAndUpdate() to update your user document by pushing the new object to the new array field registeredId. So you could re-write your post function as:
post(function (req, res, next) {
var User = mongoose.model('User'),
pid=req.body.pid,
sid=req.body.sid,
rfname=req.body.rfname,
des=req.body.des,
brand=req.body.brand,
model=req.body.model,
serial=req.body.serial,
location=req.body.location,
arr = {
'pid': pid,
'sid': sid,
'rfname': rfname,
'des': des,
'brand': brand,
'model': model,
'serial': serial,
'location': location
},
condition = { 'pemail': req.session.email },
update = {
"$push": { 'registeredId': arr }
};
User.findOneAndUpdate(
condition,
update,
function (err, doc){
if(err){}
else {
// doc contains the modified document
res.render('user/register', {'success': 'dfhlaksdhfh'});
}
}
);
});

Use populate() for two different schemas in MongoDB

I have two MongoDB collections - comments
var mongoose = require('mongoose');
var CommentSchema = new mongoose.Schema({
body: String,
author: String,
upvotes: {type: Number, default: 0},
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }
});
mongoose.model('Comment', CommentSchema);
and users
var mongoose = require('mongoose');
var UserSchema = new mongoose.Schema({
userName: String,
userJobRole: String,
userEmail: String,
userPhone: String,
userTimeZone: String,
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }
});
mongoose.model('User', UserSchema);
I want to use populate for each of these schemas in my get request. One for users and one for comments from these models.
router.get('/profiles/:profile', function(req, res, next) {
req.post.populate('users', function(err, post) {
if(err) { return next(err) }
res.json(post);
});
});
I can only figure out how to call one.
Does Mongoose allow you to populate from two schemas?
In order to populate multiple paths, you can pass a space delimited string of path names to the populate method on any document as follows:
Story
.find(...)
.populate('fans _creator') // space delimited path names
.exec()
This is taken directly from the Mongoose docs http://mongoosejs.com/docs/populate.html

Resources