Removing a child element in subdocument not working - node.js

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');
});
});
});

Related

how to fix undefined mongoose schema? [duplicate]

This question already has answers here:
Push items into mongo array via mongoose
(11 answers)
Closed 4 years ago.
I have a user schema including a few sub-schemas. I have 2 similar sub-schemas, one of them is recognised but the other one is undefined all the time.
my user schema is as follows:
var UserSchema = new Schema({
company: String,
resetPasswordToken: String,
resetPasswordExpires: Date,
isAdmin: {type: Boolean, default: false},
projects: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Project",
}
],
trackers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Tracker",
}
],
});
In the above schema, I have projects that is working very well in a post route . The form gets posted, saved and shown properly but the same route for trackers cannot be posted and give "trackers is undefined" error:
project post route:
app.post("/myprojects", function(req,res){
User.findById(req.user._id, function(err, user){
if(err){
console.log(err);
}else{
var pname = req.body.pname;
var pnumber = req.body.pnumber;
var newProject = {
pname:pname,
pnumber:pnumber,
};
Project.create(newProject, function(err, project){
if(err){
console.log(err);
}else{
user.projects.push(project);
user.save();
res.redirect("/myprojects");
}
});
}
});
});
Here is the tracker post:
app.post("/tracker", function(req,res){
User.findById(req.user._id, function(err, user){
if(err){
console.log(err);
}else{
var tname = req.body.tname;
var tnumber = req.body.tnumber;
var newTracker = {
tname:tname,
tnumber:tnumber,
};
Tracker.create(newTracker, function(err, tracker){
if(err){
console.log(err);
}else{
user.trackers.push(tracker);
user.save();
res.redirect("/tracker");
}
});
}
});
});
Please note both projects schema and tracker schemas are saved in a model folder and been required in app.js
photo of the error:
It must be giving you undefined because trackers is not saved in database on user object. You can use the following to fix the problem.
user.trackers = user.trackers || [];
user.trackers.push(tracker);

TypeError: Cannot read property 'push' of undefined - expressjs mongodb

I am trying to learn one to many relationship in MongoDB using mongoose and expressjs. I am trying to use reference method in which only id is stored as a reference.
User has already been created. Here is my code -
var mongoose = require("mongoose");
//saving application name in mongodb and connecting to it
mongoose.connect("mongodb://localhost/blog_demo_3");
//POST - title, content
var postSchema = mongoose.Schema({
title: String,
content: String
});
var Post = mongoose.model("Post", postSchema);
//USER - name email
var userSchema = mongoose.Schema({
email: String,
name: String,
//linking to many posts specific to user one to many relation
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post"
}
]
});
var User = mongoose.model("User", userSchema);
Post.create({
title: "How to cook burger pt 2",
content: "blah blah blah"
}, function(err, post){
User.find({name: "Bob Fischer"}, function(err, foundUser){
if(err)
console.log(err);
else {
//foundUser.posts.pus(post) - doesn't works
foundUser.posts.push(post._id);
foundUser.save(function(err, data){
if(err)
console.log(err)
else
console.log(data);
});
}
});
});
// User.create({
// email: "bob#foodtech.com",
// name: "Bob Fischer"
// }, function(err, createdBlog){
// if(err)
// console.log(err);
// else
// console.log(createdBlog);
// });
Please help. Thanks.
I'm sorry for not noticing such small syntax error.
User.find({name: "Bob Fischer"}, function(err, foundUser){
should be
User.findOne({name: "Bob Fischer"}, function(err, foundUser){

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);
});
});

Object.assign() Issues on Mongoose SubDocument Schema

So when I use Object.assign, (ex. Object.assign({foo:bar1},{foo:bar2}) on a particular Mongoose Subdocument Schema, the foo:bar2 obj won't overwrite the foo:bar1 obj.
In my app I have an Account Schema with two sub-document schemas, Projects & Properties. It's in the Project sub document schema that I encounter the issue.
Here are my Models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProjectSchema = new Schema({
_id: String,
name: String,
}, { strict: false })
var PropertySchema = new Schema({
_id: String,
slug: String,
name: String,
type: String,
placeholder: String,
order: Number
}, { strict: false })
var AccountSchema = new Schema({
_id: String,
name: String,
slug: String,
email: String,
properties: [PropertySchema],
projects: [ProjectSchema],
}, { strict: false })
module.exports = mongoose.model('Account', AccountSchema);
Here is a snippet of my Middleware(I think that's what it's called, please correct me if I am wrong). This is where I do the Object.assign to overwrite the particular projects' properties. If it helps I can post all the routes.
router.route('/accounts/:account_id/projects/:project_id')
.get(function(req, res) {
Project.findById(req.params.project_id, function(err, project){
if (err)
res.send(err);
res.json(project);
});
})
.delete(function(req, res){
Account.findById(req.params.account_id, function(err,account){
if (err)
res.send(err);
account.projects.id(req.params.project_id).remove();
account.save(function(err) {
if(err)
res.send(err);
res.json({message: 'Project Deleted'});
});
})
})
.put(function(req, res){
Account.findById(req.params.account_id, function(err,account){
if (err)
res.send(err);
Object.assign(account.projects.id(req.params.project_id), req.body);
account.save(function(err) {
if(err)
res.send(err);
res.json({message: 'Project Updated'});
});
})
});
// ----------------------------------------------------
router.route('/accounts/:account_id/properties/:property_id')
.get(function(req, res) {
Property.findById(req.params.property_id, function(err, property){
if(err)
res.send(err);
res.json(property);
});
})
.delete(function(req, res){
Account.findById(req.params.account_id, function(err, account){
if (err)
res.send(err);
account.properties.id(req.params.property_id).remove();
account.save(function(err){
if(err)
res.send(err);
res.json({ message: 'Successfully Deleted' });
})
})
})
.put(function(req, res){
Account.findById(req.params.account_id, function(err, account) {
if (err)
res.send(err);
Object.assign(account.properties.id(req.params.property_id), req.body);
account.save(function(err) {
if(err)
res.send(err);
res.json({message: 'Property Updated'});
})
})
});
So it's the Put Method that is giving me the issue, I can Get, Post, Delete with no issues, but the Put part for Projects is where I encounter this Object.assign issue. Funny thing is that everything works perfectly for the Property Schema Put Method, and it is basically the exact same as the Project one.
If I console.log some of the values in the Project's Put Method I get the following:
console.log(account.projects.id(req.params.project_id));
//original value logs { _id: '1486609836741', foo: 'bar' }
console.log(req.body);
//updated value logs { foo: 'barred', _id: '1486609836741' }
console.log(Object.assign(account.projects.id(req.params.project_id), req.body));
//logs the original value { _id: '1486609836741', foo: 'bar' }
So when I log the updated and original values they have equal keys, shouldn't the Object.assign work? Is the original Obj more complex then what the console.log displays, and maybe the original and updated don't have equal keys?
I am kinda stumped, any help would be greatly appreciated. Let me know if I need to post more of my code. Thanks.
Object.assign(account.projects.id(req.params.project_id), req.body);
Here, you are trying to assign to an object that is result of MongooseDocumentArray.id method call on account.projects array. Which will affect just a copy of document which is returned by function, and won't affect the original array of subdocuments.
I am new to Mongoose, but I'll suggest you trying to work with account.projects as with MongooseArray:
var project = account.projects.id( req.params.project_id ),
index = account.projects.indexOf( project );
Object.assign( account.projects[ index ], req.body);

Create an association through a single form Mongoose/express

Through a single form I'm trying to build a game object that consists of a 'game_name', and a 'game_length', and a ref association by ObjectId to a 'player'. What I have is building both objects but the player is not being saved in the players array in the Game model. Thanks for any help in advance.
Schema and Models
Game Schema/Model
var gameSchema = new mongoose.Schema({
course_name: String,
game_length: Number,
players: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Game'
}],
created: {type: Date, default: Date.now}
})
var Game = mongoose.model('Game', gameSchema);
Player Schema/Model
var playerSchema = new mongoose.Schema({
player_name: String,
})
var Player = mongoose.model('Player', playerSchema);
Post Route
app.post('/games', function(req, res){
Game.create(req.body.game, function(err, newGame){
if (err) console.log(err);
Player.create(req.body.player, function(err, newPlayer){
if (err) console.log(err);
newGame.players.push(newPlayer);
})
res.redirect('games');
})
})
It looks like you just need to call .save:
app.post('/games', function(req, res){
Game.create(req.body.game, function(err, newGame){
if (err) console.log(err);
Player.create(req.body.player, function(err, newPlayer){
if (err) console.log(err);
newGame.players.push(newPlayer);
newGame.save(function(err) {
if (err) return console.log(err);
// saved!
res.redirect('games');
});
})
})
})

Resources