I have an Angular on the frontend with node on the backend, where I show user messages that a user can delete and edit.
When I am deleting a message I also remove all the records from the users array of messages, and on the frontend that works fine, no messages that were deleted show up, but when I check in the DB, for user records, there is still one recored in the messages array of a user.
So, when I do db.users.find()
I get for the user that has all messages deleted:
"messages" : [ ObjectId("58d921cacca7c04abd100344") ], "__v" : 9
This is the messages model where I pull the message record on delete from the DB.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = require('./user');
var schema = new Schema({
content: {type: String, required: true},
user: {type: Schema.Types.ObjectId, ref: 'User'}
});
schema.post('remove', function (message) {
User.findById(message.user, function (err, user) {
user.messages.pull(message);
user.save();
});
});
module.exports = mongoose.model('Message', schema);
And this is the user model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongooseUniqueValidator = require('mongoose-unique-validator');
var schema = new Schema({
firstName: {type: String, required: true},
lastName: {type: String, required: true},
password: {type: String, required: true},
email: {type: String, required: true, unique: true},
messages: [{type: Schema.Types.ObjectId, ref: 'Message'}]
});
schema.plugin(mongooseUniqueValidator);
module.exports = mongoose.model('User', schema);
When I check the messages collection, there are no messages there at all.
Though it works fine on the frontend, I wonder why is it still showing that record in the DB, when all the messages have been deleted for the user?
Related
This question already has answers here:
pushing object into array schema in Mongoose
(2 answers)
Closed 5 years ago.
I have a mongoose schema inbox-model:
var schema = mongoose.Schema({
email: String,
data: [{
from: String,
to: String,
msg: String
}]
})
var Inbox = module.exports = mongoose.model('Inbox',schema);
module.exports.addData = function(inbox, callBack){
inbox.save(callBack);
}
I need to add to data[] array for a specific email when there's new data for that email address.
I can add data this way, through my router by calling:
var Inbox = require('inbox-model');
var inbox = new Inbox({
email: 'some#email.com',
data:[{
from: 'from',
to: 'to',
msg: 'msg'
})
Inbox.addData(inbox, Inbox);
though it doesn't add to data[] but keeps adding a whole row.
Help is much appreciated, I've searched for similar questions, but I couldn't find on adding data, just creating models with arrays.
This question has been answered a lot of time on StackOverflow. However, I'm answering it again
// Schema File - userSchema.js
const userSchema = new Schema({
email: { type: String, required: true },
data: [{
from: String,
to: String,
msg: String
}]
})
const user = mongoose.model('user', userSchema)
module.exports = user
// Service File
const user = require('./userSchema')
function someFunction(email, from, to, message) {
user.findOne({ email: email }, function(err, document) {
if (document) {
document.data.push({
from: from,
to: to,
msg: message
})
document.save(function(err) {
err != null ? console.log(err) : console.log('Data updated')
})
}
})
}
I want Users to be able to Report a File/Video only once. By pushing the users ID to a Array, then check if the user has already reported the file.
So far I am able to find the current user, then the VideoID, increment by 1 and then push it to the reportedBy array. But I am pretty lost, when it comes to checking if the current user has already reported the file. Any tips/help will be much appreciated! :-)
MY ROUTE
router.get('/report/:videoLink', function(req, res, next){
async.waterfall([
function(callback){
User.findOne({_id: req.user._id}, function(err, foundUser){
if(err) return next(err)
callback(err, foundUser)
})
},
function(foundUser, callback){
Video.findOne({videoLink: req.params.videoLink}, function(err, reportVideo){
reportVideo.reports++;
reportVideo.reportedBy.push(foundUser);
if (reportVideo.reports > 4) {
reportVideo.remove();
}
reportVideo.save(function(err){
if(err) return next();
});
res.redirect('/');
});
}
]);
});
MY SCHEMA
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var random = require('mongoose-simple-random');
var fragSchema = new Schema({
title: String,
videoLink: {type: String, unique: true, required: true},
category: String,
upVotes: {type: Number, default: 0},
downVotes: {type: Number, default: 0},
voted: {type: Boolean, default: false},
reports: {type: Number, default: 0},
reportedBy: [{ type: Schema.Types.ObjectId, ref: 'User'}],
ownByUser: {type: Schema.Types.ObjectId, ref: 'User'},
date: { type: Date, default: Date.now }
});
fragSchema.plugin(random);
module.exports = mongoose.model('Frag', fragSchema);
This should find the video only if it was reported by that user before:
Video.findOne({
videoLink: req.params.videoLink,
reportedBy: foundUser._id,
}, ...
and this should find the video only if it was not reported before:
Video.findOne({
videoLink: req.params.videoLink,
reportedBy: {$nin: [foundUser._id]},
}, ...
There are many ways to achieve that but you get the idea.
If you want to find the video anyway an then test if it was already reported by that user then something like this inside of your Video.findOne callback:
if (reportVideo.reportedBy.indexOf(foundUser._id) < 0) {
// not reported by that user yet
} else {
// already reported by that user
}
If you're using lodash then you can use:
if (_.includes(reportVideo.reportedBy, foundUser._id)) {
// already reported by that user
} else {
// not reported by that user yet
}
Make sure that you have the IDs as strings, maybe you will need to use .toString() or something like that before the comparisons.
I am building a mean stack app with express and mongoose. I have two schemas, userSchema and courseSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var courseSchema = mongoose.Schema({
title:{type:String, required:'{PATH} is required!'},
featured:{type:Boolean, required:'{PATH} is required!'},
published:{type:Date, required:'{PATH} is required!'},
courseLink:{type:String, required:'{PATH} is required!'},
user: [{type:Schema.Types.ObjectId, ref : 'User'}]
});
var Course = mongoose.model('Course', courseSchema);
module.exports = Course;
var userSchema = mongoose.Schema({
firstName: {type: String, required: true},
lastName: {type: String, required: true},
username: {
type: String,
required: true,
unique: true // creates unique index inside MongoDB
},
salt: {type: String, required: true},
hashed_pwd: {type: String, required: true},
roles:[String],
courses:[{type: Schema.ObjectId,
ref: 'Course' }]
});
I am able to create users and and courses (as an admin). What I want to do now is to allow each user add a course to his list of courses (or just click a 'like' button beside the course and that course would be added to his profile).
On the side of the controller, I have tried to check for the user id from the session, find that user and add the course to his document. But that's where I am stuck,
exports.addMyCourse = function(req, res){
console.log('user id', req.session.passport.user);
console.log('id', req.body._id);
var currentUserId = req.session.passport.user;
User.findOne({'_id':currentUserId}, function(err, doc){
console.log(doc);
});
Most of the solutions I looked at are not very clear about this. Any help would be appreciated.
RESOLVED:
I used $addToSet to add the course objects into the courses array inside the User model:
This might be useful for people searching for similar soutions:
My User schema:
var userSchema = mongoose.Schema({
firstName: {type: String, required: true},
lastName: {type: String, required: true},
username: {
type: String,
required: true,
unique: true // creates unique index inside MongoDB
},
salt: {type: String, required: true},
hashed_pwd: {type: String, required: true},
roles:[String],
courses:[{
type:Schema.ObjectId, ref:'Course'
}]
});
var User = mongoose.model('User', userSchema);
My Course schema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var courseSchema = mongoose.Schema({
title:{type:String, required:'{PATH} is required!'},
featured:{type:Boolean, required:'{PATH} is required!'},
published:{type:Date, required:'{PATH} is required!'},
courseLink:{type:String, required:'{PATH} is required!'}
});
var Course = mongoose.model('Course', courseSchema);
Inside my controllers folder, I have users.js and courses.js:
In the courses.js file, I created the addMyCourses middleware to update the User model's courses array by first retrieving the current user's id from the session and using $addToSet to insert the object and avoid duplicates at the same time. Also I made sure I am adding only the ObjectId's of the courses and not the entire course document so I won't have future problems with too much data in one document:
exports.addMyCourse = function(req, res){
var myCourse = {
title: req.body.title,
featured: req.body.featured,
published: req.body.published,
courseLink: req.body.courseLink
};
var currentUserId = req.session.passport.user;
var courseId = req.body._id;
User.update({_id:currentUserId},
{$addToSet: {"courses": courseId}},
{safe: true, upsert: true, new : true},
function(err, model) {
console.log(model);
}
);
};
Since I only had the ObjectId's of the courses inside the courses array of the User model, I had to use mongoose's populate() method to do a joint query on both models so that I get the corresponding course documents of the ids.
In users.js file:
exports.getUserCourses = function(req, res, next){
var currentUserId = req.session.passport.user;
User.findById(currentUserId).populate('courses')
.exec(function(err, data){
if(err) {
console.log(err);
}
console.log('user courses', data);
res.send(data);
})
};
I have the following schema:
var UserSchema = new Schema({
name: String,
email: { type: String, lowercase: true },
projects: [{type: Schema.ObjectId, ref:'Project'}],
//....
}
How can I add projectId by using http.put?
This is among the things that I have tried:
$http.put('/api/users/'+User._id, {'projects': project._id});
Solved it using:
$http.put('/api/users/'+User._id, {'projects': User.projects});
and in my update method:
_.extend(user, req.body);
instead of
_.merge(user, req.body);
I have a mongoose model that looks like this:
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var PictureSchema = new Schema({
listId: { type: Array, required: true },
thumb: { type: String, required: true },
large: { type: String, required: true }
});
var Picture = module.exports = mongoose.model('Picture', PictureSchema);
I am trying to update instances of this model in my router by looking up a Picture via the "listId" property. Like this:
app.put('/pictures/append', function(req, res) {
var targetListId = req.body.targetListId
, currentListId = req.body.currentListId;
Picture
.find({ listId: currentListId }, function (err, picture) {
console.log('found pic', picture);
picture.listId.push(targetListId);
picture.save(function(err, pic) {
console.log('pic SAVED', pic);
});
});
});
"currentListId" is a string, and listId is an array of currentListId's. Maybe this isn't the correct way to query a a property that is an array?
I am getting an error:
TypeError: Cannot call method 'push' of undefined
On the line:
picture.listId.push(targetListId);
But when I look up the picture models in mongo, they DO have listId arrays and some DO contain the item "currentListId" that I am using for my query.
I tried using $elemMatch and $in but I don't know if I was using them correctly.
Any idea if I am just writing my query wrong?
Specifying an Array typed field in your schema is equivalent to Mixed which tells Mongoose that field could contain anything. Instead, change your schema to something like this:
var PictureSchema = new Schema({
listId: [String],
thumb: { type: String, required: true },
large: { type: String, required: true }
});