Mongoose remove subdocuments by id method - node.js

I have two models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProjectSchema = new Schema({
title: { type: String },
images: [{
type: Schema.Types.ObjectId,
ref: 'Image'
}]
});
module.exports = mongoose.model('Project', ProjectSchema);
and
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ImageSchema = new Schema({
fileName: { type: String },
fileSize: { type: Number }
});
module.exports = mongoose.model('Image', ImageSchema);
Existing projects are filled with images as follows:
Project.findById(req.params.project_id, function(err, project) {
if (err) { res.status(400).send(err); }
var image = new Image({
fileName: req.file.name,
fileSize: req.file.size
});
image.save(function(err) {
if (err) { res.status(400).send(err); }
project.images.push(image);
project.save();
);
});
There are no problems in getting images from the project:
Project.findById(req.params.project_id)
.populate('images')
.exec(function(err, project) {
if (err) { res.status(400).send(err); }
res.status(200).json(project.images);
});
i try removing an image from a story, using Mongoose documentation:
http://mongoosejs.com/docs/subdocs.html
http://mongoosejs.com/docs/api.html#types_documentarray_MongooseDocumentArray.id
Project
.findById(req.params.project_id)
.populate('images')
.exec(function(err, project) {
if (err) { res.status(400).send(err); }
project.images.id(req.params.image_id).remove();
project.save();
});
But i keep getting errors:
/api-server/app/admin/images/index.js:170
project.images.id(req.params.image_id).remove();
^
TypeError: project.images.id is not a function
I searched here for solutions, but i only got some things on $pull from 2013.
Is the .id() method broken, or am i doing something wrong.
As i'm fairly new to mongoose, are there ways to do this better?

You just need to delete the image from the database. I hope the following code helps you.
Project
.findById(req.params.project_id)
.exec(function(err, project) {
if (err) { res.status(400).send(err); }
project.save();
Image.remove({"_id":project.images._id},function(){})
});

You can delete subdocuments by using findByIdAndUpdate and $pull.
Seting options to {new: true} overwrites the existing document
var fieldsToRemove= {
$pull: {
images: {
_id: req.params.type
}
}
};
var options = { new: true };
Project.findByIdAndUpdate(req.params.project_id, fieldsToRemove, options,
function(err, project) {...
it will remove the subdocument with specified _id

Related

Need to do a many comments belong to one article relation MongoDB

I am using Mongoose/MongoDB and I am trying to associate many comments to one article. My app begins by scraping from a website and then the user has the option to save each article that was scraped into the MongoDB. When the user chooses to save one article, I save it into database. So when a user clicks on one of their saved articles, they can comment on them. Each article has its own comment section I need to retrieve the correct comments.
//My post comment request in JS file
function postComment(){
var articleComment = {
comment: $('#comment').val().trim()
}
$.post('/comments/' + articleID, articleComment).done(function(data){
$('.main-popup').fadeOut();
console.log('DONNE', data);
});
}
//Post route in controller
router.post('/comments/:id', function(req, res){
var newComment = new Comment(req.body);
newComment.save(function(err, doc){
if(err){
console.log(err);
}else{
Comment.findOneAndUpdate({ "_id": doc._id }, { "article": req.params.id }).exec(function(err, doc){
if(err){
console.log(err);
res.send(err);
}else{
res.send(doc);
}
});
}
});
});
//Get request to get correct comments when clicked on specific article
function showCommentBox(){
$('.comments').empty();
$('#comment').val("");
articleID = $(this).attr('data-article-id');
$.get('/comments/' + articleID, function(data){
if(data.article){ //This is undefined*********************
for(var x = 0; x < data.comment.length; x++){
$('.comments').append("<div><h2>" + data.comment[x].comment + "</h2><span><button>×</button></span></div>");
}
}
$('.main-popup').fadeIn();
});
}
//Get route in controller
router.get('/comments/:id', function(req, res){
Comment.findOne({ "article": req.params.id }).populate("article").exec(function(err, doc){
if(err){
console.log(err)
}else{
res.json(doc);
}
});
});
//Article Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ArticleSchema = new Schema({
title: {
type: String
},
link: {
type: String
},
description: {
type: String
},
img: {
type: String
}
});
var Article = mongoose.model("Article", ArticleSchema);
module.exports = Article;
//Comment Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CommentSchema = new Schema({
comment: {
type: String
},
article: {
type: Schema.Types.ObjectId,
ref: 'Article'
}
});
var Comment = mongoose.model('Comment', CommentSchema);
module.exports = Comment;
First, you're missing $set when you do .findOneAndUpdate. Also I think you should convert a string to Mongo ObjectId before setting it.
So it might look likt this:
const ObjectId = mongoose.Types.ObjectId;
Comment.findOneAndUpdate({ "_id": doc._id }, {$set: {"article": new ObjectId(req.params.id) }})
Also you don't need to make 2 database calls. You could article id before saving newComment and then simply send it as a response like this:
//Please notice that mongoose.Schema.Types.ObjectId and mongoose.Types.Object are different types.
//You need this one here:
const ObjectId = mongoose.Types.ObjectId;
router.post('/comments/:id', function(req, res){
var newComment = new Comment(req.body);
newComment.article = new ObjectId(req.params.id);
newComment.save(function(err, doc){
if (err) {
console.error(err);
res.send(err);
return;
}
res.send(doc);
});
});

Removing a child element in subdocument not working

I'm fairly new to Mongoose and don't think my approach on deleting an item in a subdocument is the right one.
I have the following schema setup:
//DEPENDENCIES
var mongoose = require('mongoose');
var contactSchema = new mongoose.Schema({
name:{type:String},
age:{type:Number}
});
var phoneSchema = new mongoose.Schema({
number:{ type: String },
phoneType:{ type: Number }
})
var memberSchema = new mongoose.Schema({
firstname: {
type: String
},
lastname: {
type: String
},
phone:[phoneSchema],
contacts:[contactSchema]
});
//RETURN MODEL
module.exports = mongoose.model('member', memberSchema);
To remove an item from the phone, in my Express API, I first find the parent then reference "remove" for the child ID, like this. But it does not work.
router.route('/owner/:ownerId/phone/:phoneId')
.delete(function(req, res){
Member.findOne({_id: req.body.ownerId}, function(err, member){
member.phone.remove({_id: req.body.phoneId}, function(err){
if(err)
res.send(err)
res.json({message: 'Success! Phone has been removed.'})
});
});
});
Figured out that I was looking for req.body and was actually needing req.params.
Also found right syntax on Mongoose docs:
router.route('/owner/:ownerId/phone/:phoneId')
.delete(function(req, res){
Member.findOne({_id: req.params.ownerId}, function(err, member){
member.phone.id(req.params.phoneId).remove();
member.save(function (err) {
if (err) return handleError(err);
console.log('the sub-doc was removed');
});
});
});

How to insert new document to mongodb?

I have schema created now i want to save new document to collection but its not happening with below code, I am new to mongodb any help will be appreciated.
routes.js
var Diagram = require('./diagram');
router.post('/saveNewDiagram',function(req,res){
Diagram.save(req.body);
});
diagram.js
var diagram = require('./diagram.model');
var mongoose = require('mongoose');
var Diagram = {
update: function(req, res) {
diagram.update({
_id: req._id
}, {
$set: {
'string': req.string
}
}, function(err, result) {
if (err) {
return res.status(500).send(err);
} else {
console.log("successfully updated document");
}
});
},
save: function(req, res) {
var newDiagram = new diagram();
newDiagram.save(req.body);
}
}
module.exports = Diagram;
model.js
var DiagramSchema = new mongoose.Schema({
text: String,
owner: {type: String, ref:'User'},
groups: [{type: String, ref: 'Group'}],
users: [{type: String, ref: 'User'}],
string: String
});
module.exports=mongoose.model('Diagram', DiagramSchema);
You did wrong in save function, you save function should be like
save: function(req, res) {
var newDiagram = new diagram(req.body);
newDiagram.save();
}
and make sure req.body only have string and/or text fields. You may like to add following check
save: function(req, res) {
var diagramData = {
string: req.body.string,
text: req.body.text
}
var newDiagram = new diagram(diagramData);
newDiagram.save();
}

Query populated document with mongoose

I have following mongodb/mongoose data model::
var UserSchema = new Schema({
name: String
, roles: [] // admin or client
/* others object */
});
mongoose.model('User', UserSchema);
var ReviewSchema = new Schema({
title: String
, user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Review', ReviewSchema);
Now I want to get all review where user's role is admin. I have tried the following way:
Review
.find( { 'user.roles': 'admin' } )
.populate('user')
.exec(function(err, review) {
console.log("review : ", review); // null
});
NB: "mongoose": "^4.2.9",
How can I solve this problem? Thanks in advance.
I hope, this code may be solved your problem
Review.find()
.populate('user', null, { roles:"admin" })
.exec(function (err, review) {
if(err) {
console.log(err);
res.json(err);
}else {
var review = review.filter(function (review) {
return review.user !== null;
}).pop();
console.log(review);
res.json(review);
}
});

Node.js express download from mongodb

I want to write a rest api, with which i am able to download some data. All datas were stored in a mongodb. I don't know what to pass to the download method, to make it possible.
Here is my current code:
router.get('/download/:productId/:username/:token', function (req, res) {
var auth = require('../provider/authProvider.js');
var authInst = new auth();
authInst.checkAuth(req.params.username, req.params.token, res, function (err, obj) {
if (obj == true) {
res.status(200);
// here is my problem, what to pass to the download-method
res.download('');
}
});
});
I could not find anything else, than passing paths to the download method.
Does anyone has an idea how to solve my problem?
I assume you know how to set up mongoose environment, putting config, connecting to MongoDB. If not please refer to my answer here.
Now let's say we have a Document in MongoDB as Blog.
So we need to create a model for Blog so that we can do CRUD operations using Mongoose ORM.
you need mongoose module for this to be included in your project.
so run this command from your project root directory, it will automatically download mongoose for you.
npm install mongoose --save
BlogModel.js
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var BlogSchema = new Schema({
"title" : { type: String },
"user_id" : { type: String },
"blog_uri" :{ type: String },
"post_date" : { type : Date, default: Date.now},
"body" : { type: String, default: '' },
"comments" : [
{ 'content' : { type: String },
'user_id' : { type: String },
'comment_date' : { type: Date },
'votes' : [
{
'user_id' : { type: String }
}
]
}
],
"hidden" : {type:Boolean, default: false }
});
mongoose.model('Blog', BlogSchema);
So let's create a separate file called BlogController.js where we will write methods for CRUD.
var mongoose = require('mongoose');
var Blog = mongoose.model('Blog');
var ObjectId = require('mongoose').Types.ObjectId;
exports.create = function(req,res){
var blog = new Blog(req.body);
blog.save(function(err){
if(err)
res.json({message: "Error occured while saving"});
else{
res.redirect('/home');
}
});
};
exports.getAll = function(req,res){
Blog.find(function(err,blogs){
if(err){
res.send(err);
}else{
res.json(blogs);
}
});
};
exports.get = function(req,res){
var id ;
try{
id = new ObjectId(req.params.id);
Blog.findById(id,function(err,blog){
if(err){
res.send(err);
}else{
res.render('blog.ejs', {
blog: blog
});
}
});
}catch(e){
res.send(404);
}
};
exports.update = function(req,res){
var id ;
try{
id = new ObjectId(req.params.blog_id);
Blog.findById(id,function(err,blog){
if(err){
res.send(err);
}
blog.save(function(err){
if(err)
res.send(err);
res.render('blog.ejs', {
message: "Blog Updated successfully"
});
});
});
}catch(e){
res.send(404);
}
};
exports.delete = function(req,res){
var id ;
try{
id = new ObjectId(req.params.blog_id);
Blog.remove({_id:id},function(err,blog){
if(err){
res.send(err);
}
res.render('blog.ejs', {
message: "Blog deleted successfully"
});
});
}catch(e){
res.send(404);
}
};
So this was about CRUD using Mongoose. I usually don't use res.render(..) in my projects because i put Templating logic in front end. I just use res.json(..) and pass the json data to the the frontend. So please go ahead and try. I hope i answered your question. You can refer to
this repo, for better example. Here i got a very clean CRUD implementation.

Resources