Mongoose populate - Node.JS creating multiple objects - javascript

Task I have is to make a array of i.e. dishes that logged user is selecting as his favourite. Problem is that instead of one array of objectIDs i.e. dishes:[123456,5678910], i get two separate objects for same user with only one dish id in the array.
I presume that problem is in my schema, so can someone give me an idea?
var favoriteSchema = new Schema({
timestamps: true,
dishes: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Dish'
}],
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
Edit>> My post method as demanded
.post(Verify.verifyOrdinaryUser, function (req, res, next) {
Favorites.create(req.body, function (err, favorite) {
if (err) throw err;
console.log('favorite created!');
var id = favorite._id;
favorite.postedBy = req.decoded._doc._id;
favorite.dishes.push(req.body);
favorite.save(function (err, favorite) {
if (err) throw err;
console.log('Updated Favorites!');
res.json(favorite);
});
});

Your post method is fine for the first time you want to add a favorite dish. The next time you add a dish for the same user you should call
Favorites.findOne({postedBy: req.decoded._doc._id}, function (err, favorite) {
favorite.dishes.push(req.body);
favorite.save(function (err, favorite) {
if (err) throw err;
res.json(favorite);
});
})

Related

cannot insert document into mongodb collection node.js

I am very new to mongodb, literally just installed yesterday. I created a collection programmatically, and now am trying to insert a document into the already created collection.
here's what I have:
MongoClient.connect(uri, function(err, db) {
if (err) throw err;
db.socialPosts.insert( { title: "My First Post", description: "This is my first post desc" } )
console.log("success")
db.close();
});
});
the name of the collection is socialPosts, and I am just trying to insert a doc into it. The error it is throwing is:
TypeError: Cannot read property 'insert' of undefined
how do i fix this?
based on the answers above, and some research online, I have come across this solution:
client.connect().then (() => {
const database = client.db("myFirstDatabase");
const socialPosts = database.collection("socialPosts");
MongoClient.connect(uri, function(err, db) {
if (err) throw err;
const doc = { title: postTitle, description: postDescription, instagramLink: instagramLink };
socialPosts.insertOne(doc)
db.close();
});
});
this works seamlessly :)

Why the data is being stored twice using mongoose?

I want to save a number of data in a property call cases. What I did was to iterate a list of data that I want to store, and then adding each data to the document's property. But the problem is that each data is being stored twice. I found a person in github who had the same issue, he said the problem was with nodemon, but I ran the sever again without nodemon and is the same problem.
Also found a question in stack saying that when a callback is applied it results in saving it twice, also the case is diferent from mine:
Why does using mongoose callback result in saving data twice?
I tried removing the callback, but I still have the same problem. (I dont think that a callback might do that)
This is the code:
var UserSchema = Schema({
user: {type: String},
password: {type: String},
name: {type: String},
privilege: {type: String},
cases: {type: Array}
})
var user = db.model('User', UserSchema , "users");
app.post("/addCases", function(req, res){
user.find({user: req.body.user}, async function(err, doc) {
if(err) {
console.log(err);
} else {
for (const iterator of req.body.list) {
await user.updateOne({user: req.body.user},
{ $push: {cases: iterator}}, {useFindAndModify: false}, function(err, raw) {
if(err) {
console.log(err);
} else {
console.log(value + ' <----- Value');
}
});
}
}
});
});
I think your problem might be related to you not ending the request in your server's code. After doing the modifications in your db, you should send a response to your front-end, if not it might try to repeat the request and you would end up with your endpoint being called two times.
Try something like:
app.post("/addCases", function(req, res){
user.find({user: req.body.user}, async function(err, doc) {
if(err) {
console.log(err);
} else {
for (const iterator of req.body.list) {
await user.updateOne({user: req.body.user},
{ $push: {cases: iterator}}, {useFindAndModify: false}, function(err, raw) {
if(err) {
console.log(err);
} else {
console.log(value + ' <----- Value');
}
});
}
}
// New code
res.json({ ok: true });
});
});

Node.js and mongoose update parameters

task.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var taskSchema = new Schema({
status: {type: String, default: 'TO-DO'},
contents: String,
createDate: {type: Date, default: Date.now},
author: {type:String, defafult:'Chris'}
});
module.exports = mongoose.model('Task', taskSchema);
task-controller.js
var Task = require('../models/task.js');
exports.update = function(req, res) {
Task.update({
contents : req.body.contents
}, {
status : req.body.status
}, function(err, numberAffected, raw) {
if (err) {
throw err;
}
console.log('The number of updated documents was %d', numberAffected);
console.log('The raw reponse from MongoDB was', raw);
});
res.redirect('/');
res.end();
};
At task-controller.js, You can see "numberAffected" and "raw" parameters.
However when I execute the code, the console displays
The number of updated documents was NaN
The raw reponse from MongoDB was undefined
So I searched the reference, but I can't find those kinds of parameters.
Are those parameters valid?
That is because Model.update returns a callback with only two parameters first parameter being err and second numAffected (which is Object not a number) as follows :
var Task = require('../models/task.js');
exports.update = function(req, res) {
Task.update({
contents : req.body.contents
}, {
status : req.body.status
}, function(err, numberAffected) {
//numberAffected is Object
if (err) {
throw err;
}
console.log('The number of updated documents was ', numberAffected); //Remove %d as numberAffected is not a number
});
res.redirect('/');
res.end();
};

Send 2 array to view in sailjs

I am new to sails.js and when I'm trying to learn it by making a simple web app, I encountered a problem. My app is about class management. My model has 3 table: student, course and list. The student table save information about students, course save information about courses. The list.table save information about which student is in a course and their mark, their absent days in this class. I used res.view() and it worked for any view that need one array. However, when I try to write function which need information from 2 model: student and course, res.view() didnt help (or I dont know to do it properly)
module.exports = {
'new': function(req, res, next) {
Course.find(function foundCourses (err, courses) {
if (err) return next(err);
res.view({courses: courses});
});
/* Student.find(function foundStudents (err, students) {
if (err) return next(err);
res.view({
students: students
});
}); */
},
//more other code here
};
There, I want to send both array to view but I dont know how. Sails.js only let me send one array if I do like that. Please help me . Thank you a lot!
You can't call res.view twice. You need to gather all data first and than send it to view.
2 methods:
module.exports = {
'new': function(req, res, next) {
var foundCourses = function (err, courses) {
if (err) return next(err);
Student.find(function foundStudents (err, students) {
if (err) return next(err);
res.view({
courses: courses,
students: students
});
});
});
Course.find(foundCourses);
},
//more other code here
};
or you can use async.parallel
module.exports = {
'new': function(req, res, next) {
var dataCallback = function (err, data) {
if (err) return next(err);
var courses = data[0];
var students = data[1];
res.view({
courses: courses,
students: students
});
};
async.parallel([
function(callback) {
Course.find(callback);
},
function(callback) {
Student.find(callback);
}
],dataCallback);
},
};

Bypass mongoose getter

I was trying to use mongoose getter to cast all user password before send out. It works perfectly.
However, on method "comparePassword", I need the passwordstring to compare sothen I can authenticate.
Is there a way to bypass the getter under certain conditions in mongoose? Thanks in advance!
Code Example:
function castpassword (pw) {
return 'keyboard cat';
}
var AccountSchema = new Schema({
password: { type: String, get: castpassword }
});
AccountSchema.methods.comparePassword = function (candidatePassword, cb) {
// random hash vs keyborad cat === not authenticated
crypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
....
Account.findById( someId, function (err, found) {
console.log(found.password); // 'keyboard cat'
});
You can use mongoose 'lean' to skip all mongoose magic and just pull out a json object.
Account
.findById(someId)
.lean()
.exec(function (err, found) {
console.log(found.password); // actual password
// you can not use mongoose functions here ex:
// found.save() will fail
})
Another option would be to set password to 'select: false' in the schema.
var AccountSchema = new Schema({
password: { type: String, select: false }
});
This way anytime you pull out the document the password field would not be there at all unless you specifically as for it.
Account
.findById(someId, function (err, found) {
console.log(found.password); // undefinded
})
Account
.findById(someId)
.select('password') // explicitly asking for password
.exec(function (err, found) {
console.log(found.password); // actual password
})
Using this.toObject() in mongoose will bypass all getter and setter settings in mongoose since it change it to plain JSON data
AccountSchema.methods.comparePassword = function (candidatePassword, cb) {
// keyboard cat vs keyboard cat === authenticated
crypt.compare(candidatePassword, this.toObject().password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};

Categories