MongoDB vanishes attributes on save - node.js

Hi im using MongoDB + Mongoose and some strange magic happens in my app.
Ive defined my Schema as
var schema = mongoose.Schema({
username: {type: mongoose.Schema.ObjectId, ref: 'Profile' , required:true},
user: {type: mongoose.Schema.ObjectId, ref: 'Profile' , required:true},
message: String
});
As I save my Document the new entry has ben saved and stored. It has a message and a ref on Profile in username but the user field is missing.
Same happens if I rename it to userId :/ Registered a pre save listener : already missing in my callback before save
There is no Error and I do not know how to handle this situation. Please help. Would call the a team but I can not afford
Edit :
Full Schema
var mongoose = require('mongoose');
var schema = mongoose.Schema({
username: {type: mongoose.Schema.ObjectId, ref: 'Profile' , required:true},
user: {type: mongoose.Schema.ObjectId, ref: 'Profile' , required:true},
message: String
});
var autoPopulate = function(next) {
this.populate('user');
this.populate('username');
next();
};
var autoReduce = function(next) {
if(this.username){
this.username = this.username._id;
}
if(this.user){
this.user= this.user._id;
}
next();
};
schema.
pre('findOne', autoPopulate).
pre('find', autoPopulate).
pre('save', autoReduce);
module.exports = mongoose.model('News',schema);
Request Body
{
"message": "Hi",
"username": {
"_id": "5a736607bee0360014fb28e6",
"name": "Juventus Florin"
},
"user": {
"_id": "5a736607bee0360014fb28e6",
"name": "Juventus Florin"
}
}
Code
app.put("/api/news", function(request, response) {
response.header("Content-Type", "application/json");
var payload = request.body;
new News(payload).save(function(err) {
if(err){
response.status(500).send({"message": "This is an error!", "error":err, "payload":payload});
}else{
response.status(200).send(payload);
}
});
});
After saving there is an new entry , looks like (username is populated)
{
"message": "Hi",
"username": {
"_id": "5a736607bee0360014fb28e6",
"name": "Juventus Florin"
},
"_id":"5a736607bee0360014fb278h"
}

Solution :
On 1 to 1 references there is no need to
this.user = this.user._id;
Only on 1 to Many references. Removed the pre save listener autoReduce and it works

Related

saving complex structure in mongodb using express and mongo

I'm new to mongodb, node and express. I I'm trying to save these data in mongodb.
I have staff.model.js as follows
let StaffSchema = new Schema({
staffcode:String,
firstname:String,
lastname: String,
type: String,
department:String,
dateofjoin:Date,
lastworkingday:Date,
teaching:[ {type:Schema.Types.ObjectId, ref:'Teaches'} ]
});
I have another schema named teaches as follows
let TeachesSchema = new Schema({
standard:{type: Schema.Types.ObjectId, ref: 'Standard'},
subjects:[{type: Schema.Types.ObjectId, ref: 'Subject'}]
});
another schema of standards as follows
let StandardSchema = new Schema({
name:String,
medium:String,
section:String
});
another schema subjects as follows
let SubjectSchema = new Schema({
name:{ type: String, required: true, max: 25 }
});
finally I'm trying to save data in mogodb as like
exports.staff_create = function(req, res){
let staff = new Staff({
staffcode:req.body.staffcode,
firstname:req.body.firstname,
lastname: req.body.lastname,
type: req.body.type,
department:req.body.department,
dateofjoin:req.body.dateofjoin,
teaching:req.body.teaching
});
staff.save(function(err){
if(err){
return next(err);
}
res.send('Staff created successfully');
});
};
making api call from postman with input like this
{
"staffcode": "STF0003",
"firstname": "Joh Doe",
"lastname": "Moy",
"type": "teaching",
"department": "physics",
"dateofjoin": "2018-06-01",
"teaching": {
"standard": {
"_id": "5cb8ff551a1c1a2514fa467c",
"name": "1",
"medium": "English",
"section": "A"
},
"subjects": [
{
"_id": "5cb8ed65c068b22f5489d050"
},
{
"_id": "5cb8ed6bc068b22f5489d051"
}
]
}
}
what is wrong in this? I'm not able to get success response in postman request.
your schema design is coming from relational databases. However you can do what you ask by using populate.
a better way would be to use embedded documents instead of referrals in some places check this answer about MongoDB relationships: embed or reference?

Getting error about $pushAll when going to endpoint, but not using it anywhere

I have a strange one...
I've developed an api with Node/Express/Mongoose using Mongodb 3.4.9, now it's 3.4.17.
I have no ideal why, but for some reason a block of code I have been using for ages is throwing an error:
{name: "MongoError", message: "Unknown modifier: $pushAll", driver: true, index: 0, code: 9,…}
code: 9
driver: true
errmsg: "Unknown modifier: $pushAll"
index: 0
message: "Unknown modifier: $pushAll"
name: "MongoError"
Here is the code:
router.route('/addemail/:id')
// ADD EMAILS
.put(function(req, res){
Profile.findOne({'owner_id':req.params.id}, function(err, profile){
if(err)
res.send(err);
profile.emails.push({
email_type: req.body.email_type,
email_address: req.body.email_address
})
profile.save(function(err){
if(err)
res.send(err);
res.json(profile);
});
});
});
As you can see, I'm not using $pushAll in this block of code, or actually anywhere in my code.
What else could be causing this???
Thanks for any guru advise.
Update: Here is my model for the profile and I'm including the emails model next:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// SUBDOCUMENTS
var AddressesSchema = require('./profile/addresses');
var BusinessesSchema = require('./profile/businesses');
var EmailsSchema = require('./profile/emails');
var PhonesSchema = require('./profile/phones');
var SocialSchema = require('./profile/social');
// PROFILE (PARENT) MODEL
var ProfileSchema = new Schema({
//PROFILE INFO
owner_id: {
type: String,
require: true,
unique: true
},
notice: {
type: Number, // 1=profile, 2=profile and cards
},
first_name:{
type: String
},
last_name:{
type: String
},
initial:{
type: String
},
birthday:{
type: Date
},
highschool:{
type: String
},
college:{
type: String
},
facebook:{
type: String
},
linkedin:{
type: String
},
linkedin_bus:{
type: String
},
twitter: {
type: String
},
google: {
type: String
},
pinterest: {
type: String
},
user_image: {
type: String
},
contacts:[{
type:Schema.Types.ObjectId,
ref:'Contact'
}],
//SUBDOCUMENTS
emails:[EmailsSchema],
phones:[PhonesSchema],
addresses:[AddressesSchema],
businesses:[BusinessesSchema],
social:[SocialSchema]
});
module.exports = mongoose.model('Profile', ProfileSchema);
Here is what the emails model looks like:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// CONTACT (PARENT) MODEL
var EmailSchema = new Schema({
//CONTACT INFO
email: {
type: String,
require: true
},
date_registered: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Email', EmailSchema);
Mongoose probably creates a $pushAll under the hood which, however, has been removed in newer version of MongoDB as you can see here. So this is why you get the error.
I suggest you upgrade to the latest version of Mongoose which will fix this.
Also see these discussions on the Mongoose repo: https://github.com/Automattic/mongoose/issues/4455
https://github.com/Automattic/mongoose/issues/5574
Pardon me for asking but why don't you just:
// ADD EMAILS
.put(function(req, res) {
Profile.update({'owner_id': req.params.id},
{
$addToSet: {
email_type: req.body.email_type,
email_address: req.body.email_address
}
});
});
It seems you just want to add an object to an array in a mongo document based on owner_id. $addToSet does that.
You should get advantage of some mongodb nice features i.e. you could do these:
Profile.findOneAndUpdate({'owner_id':req.params.id},{addToSet:{emails:[ email_type: req.body.email_type, email_address: req.body.email_address]}}, function(err, profile){
if(err){
res.send(err);
} else {
res.json(profile);
}
}

mongoose query with $in property

var mongoose = require('mongoose');
var FriendSchema = new mongoose.Schema({
requester: {
type: String,
required: true,
},
recipient: {
type: String,
required: true,
},
});
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var Friend = mongoose.model('Friend', FriendSchema);
module.exports = Friend;
I am trying to query it by using
Friend.find({"requester": { $in: [some id value]}}, function(err, fee){
console.log(fee.recipient);
});
and having it return the recipient id value..
Any suggestions would really be helpful, thank you.
you can use projection of mongo.db
the structure is like below ,
find(condition , requirefield , callback);
below is the example in which the fee will contain only the recipient
Friend.find({"requester": { $in: [some id value]}}, { _id : 0 , requester : 0 } ,function(err, fee){
console.log(fee.recipient);
});
you can refer https://docs.mongodb.com/manual/reference/method/db.collection.find/#projections for more reference.

MongoDB Mongoose schema design

I have a schema design question. I have a UserSchema and a PostSchema.
var User = new Schema({
name: String
});
var Post = new Schema({
user: { type: Schema.Types.ObjectId }
});
Also, user is able to follow other users. Post can be liked by other users.
I would like to query User's followers and User's following, with mongoose features such as limit, skip, sort, etc. I also want to query Post that a user likes.
Basically, my only attempt of solving this is to keep double reference in each schema. The schemas become
var User = new Schema({
name: String,
followers: [{ type: Schema.Types.ObjectId, ref: "User" }],
following: [{ type: Schema.Types.ObjectId, ref: "User" }]
});
var Post = new Schema({
creator: { type: Schema.Types.ObjectId, ref: "User" },
userLikes: [{ type: Schema.Types.ObjectId, ref: "User" }]
});
so, the code that will be used to query
// Find posts that I create
Post.find({creator: myId}, function(err, post) { ... });
// Find posts that I like
Post.find({userLikes: myId}, function(err, post) { ... });
// Find users that I follow
User.find({followers: myId}, function(err, user) { ... });
// Find users that follow me
User.find({following: myId}, function(err, user) { ... });
Is there a way other than doing double reference like this that seems error prone?
Actally, you don't need the double reference. Let's assume you keep the following reference.
var User = new Schema({
name: String,
following: [{ type: Schema.Types.ObjectId, ref: "User" }]
});
You can use .populate() to get the users you're following:
EDIT: added skip/limit options to show example for pagination
User.findById(myId).populate({ path:'following', options: { skip: 20, limit: 10 } }).exec(function(err, user) {
if (err) {
// handle err
}
if (user) {
// user.following[] <-- contains a populated array of users you're following
}
});
And, as you've already mentioned ...
User.find({following: myId}).exec(function(err, users) { ... });
... retrieves the users that are following you.

mongoose populate not populating an array

I am facing an issue where mongoose query is not populating an array type.
Here is institute schema
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var InstituteSchema = new Schema({
name: String,
address: String,
city: String,
country: String,
zip: String,
owner: { type: mongoose.Schema.ObjectId, ref: 'User' },
teachers: [{type: mongoose.Schema.ObjectId, ref: 'Teacher'}],
categories: [String],
created : { type : Date, default : Date.now }
});
module.exports = mongoose.model('Institute', InstituteSchema);
And here is teacher Schema
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TeacherSchema = new Schema({
education: [{degree: String, instituteName: String}],
dob: Date,
photoUrl: String,
phoneNumber: String,
owner: {type: mongoose.Schema.ObjectId, ref: 'User'},
institutes: [{type: mongoose.Schema.ObjectId, ref: 'Institute'}],
subjects: [{type: mongoose.Schema.ObjectId, ref: 'Subject'}],
created : { type : Date, default : Date.now }
})
module.exports = mongoose.model('Teacher', TeacherSchema);
Here is a method which queries the institute by owner id
exports.mine = function (req, res, next) {
var ObjectId = mongoose.Types.ObjectId;
var userId = new ObjectId(req.user._id);
Institute.find({
owner: userId
}).populate('teachers').exec(function (err, institute) {
if (err) return next(err);
if (!institute) return res.json(401);
res.json(institute);
});
};
I can see from the db that institute has teacher added
db.institutes.find();
{
"_id" : ObjectId("554719a9f5be11c6d4369264"),
"owner" : ObjectId("5547199bf5be11c6d4369263"),
"country" : "USA",
"name" : "Raghvendra Singh",
"address" : "38589 Royal Ann Cmn",
"city" : "Fremont",
"zip" : "94536",
"created" : ISODate("2015-05-04T07:03:05.569Z"),
"categories" : [ "IIT", "Medical" ],
"teachers" : [ ObjectId("55471965f5be11c6d436925f") ],
"__v" : 3
}
But somehow the query method doesn't populate the teachers collection. The weird thing is that i don't even get the collection with object ids and it returns and institute with empty teacher array.
And when i remove the .populate('teachers') from the method call it indeed returns the teacher array with object ids.
I looked at the documentation and i can't see what am i doing wrong.
First you need to change your Model slightly as mention for teachers feild.
teachers: [ { teacher: { type: Schema.ObjectId, ref: "Teacher" } } ]
exports.mine = function (req, res, next) {
var ObjectId = mongoose.Types.ObjectId;
var userId = new ObjectId(req.user._id);
Institute.find({
owner: userId
}).populate('**teachers.teacher**').exec(function (err, institute) {
if (err) return next(err);
if (!institute) return res.json(401);
res.json(institute);
});
};
Then, change your populate parameter to teachers.teacher . It will work

Resources