JAVASCRIPT MongoDB delete specific object from array - javascript

I have got a nested array brought within a query from database, query brings the following:
{
_id: new ObjectId("623rf3f22275f399f88bb"),
first_name: 'Are',
last_name: 'You',
email: 'helping#stackoverflow.me',
password: '$2a$10$BSmezAjYkqU.234t65sT1pPOhg5jxosYrFzwjqXM3On3v.b7p46K1WS',
username: 'lcd1',
Messages: [
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
},
{
msgcontent: 'The user whatever said: whatsup.'
}
]
}
And I have a button for deleting in each of the brought iterations of a for loop on the page, how do I delete a specific message from the array using the button displayed from the iteration on the page?
I've got this displaying messages:
<% if (messages.length > 0) { %>
<% for (let nr = 1; nr <= messages.length; nr++) { %>
<div class="cardmsgpage">
<div class="displaymsg">Message <%= [nr] %> : <%= messages[nr-1].msgcontent %> </div>
<div class="sideways">
<form action="/deletemsg:id" method="POST">
<button class="msgpagebtn" type="submit"><img class="icon" src="/images/trash-can-solid.svg"></button>
</form>
</div>
</div>
<% } %>
and on the POST method I have:
app.post('/deletemsg', function (req, res) {
for (let nr = 0; nr <= messages.length; nr++) {
message = messages[nr];
}
users.findOne({}).then(result =>{
console.log(result);
users.deleteOne( { "Messages" : [messages[nr]] } );
console.log(result);
})
});
Can anyone tell me how I can delete only the message matching the button of the iteration that displayed it?

If I understood your concern correctly,
I think you are trying to say that you are displaying all the messages(as mentioned above in the problem) as Message i : <message content> and a delete button next to it, upon clicking which sends a POST request to the server to delete the message you've clicked on.
According to me, you can do one thing.....
When post request is made, it should be known to the handeler that which database record is to be modified(object id) and then inside of it which message is to be deleted.
To identify the message which should be deleted you can provide unique id to each of the message object inside your Messages property in database record or you can make a separate message schema and model and use it to store message in Messages array, then each message in Messages array will have unique id.
And then, we can use combination of the database record id(objectId) and the message id to delete the specific message from a specific database record.
Each message having unique id looks like...
{
_id: new ObjectId("623rf3f22275f399f88bb"),
first_name: 'Are',
last_name: 'You',
email: 'helping#stackoverflow.me',
password: '$2a$10$BSmezAjYkqU.234t65sT1pPOhg5jxosYrFzwjqXM3On3v.b7p46K1WS',
username: 'lcd1',
Messages: [
{
_id: <message-id>,
msgcontent: 'The user whatever said: whatsup.'
},
{
_id: <message-id>,
msgcontent: 'The user whatever said: whatsup.'
}
...........
]
}
Pass record's objectId and Messages array or whole object to the ejs file. Your action field of the form looks like /deletemsg/:record_id/:msg_id.
Inside your ejs file
// record_id is objectId of database record
<% if (messages.length > 0) { %>
<% for (let nr = 1; nr <= messages.length; nr++) { %>
<div class="cardmsgpage">
<div class="displaymsg">Message <%= [nr] %> : <%= messages[nr-1].msgcontent %> </div>
<div class="sideways">
<form action="/deletemsg/record_id/messages[nr-1]._id" method="POST">
<button class="msgpagebtn" type="submit"><img class="icon" src="/images/trash-can-solid.svg"></button>
</form>
</div>
</div>
<% } %>
Handle the POST request
app.post('/deletemsg/:record_id/:msg_id', function (req, res) {
users.findOne({_id: req.params.record_id }).then(result =>{
if(result){
console.log(result);
let messages = result.Messages;
// you have msg id, you have to delete that message
let idxToDelete = messages.findIndex(msg=>{
return msg._id === req.params.msg_id;
});
if(idxToDelete != -1)
messages.splice(idxToDelete, 1);
result.Messages = messages;
result.save().then(()=>{
console.log("Message deleted!!!");
}).catch(err=>{
console.log(err);
});
}
})
});
That's it......
Note:- you will have message and record schema like this below.....
const msg_schema = mongoose.Schema({
msgcontent: {type: String}
});
const record_schema = mongoose.Schema({
// everything same ......
// Messages array will have msg_schema types
Messages: [msg_schema]
});

Related

Why is it showing that the function is not defined? It does log the results in console, I am just trying to list the first name

I have a restAPI backend that I am trying to get data from. I am using NodeJS but for some reason, the data loads in the console as JSON but when I try to print it in the new webpage I get an error
TypeError: /Final part 2/views/pages/letseat.ejs:11
9| </div>
10| <!-- Right here it takes every value that we got back and then puts it into a list item -->
>> 11| <% userlist.forEach(function(userlist) { %>
12| <ul class="list-group list-group-numbered">
13| <input type="checkbox" name=<%= userlist.firstname %>
14| <li class="list-group-item"><%= userlist['firstname'] %>, By: <%= userlist['lastname' ]%> </li>
Cannot read properties of undefined (reading 'forEach')
But I do get the data in JSON in the terminal
data: [
{
firstname: 'John',
lastname: 'Boyle',
numberofplaces: null,
user_id: 1
},
{
firstname: 'Ruben',
lastname: 'Holt',
numberofplaces: null,
user_id: 3
},
{
firstname: 'Tim',
lastname: 'Diaz',
numberofplaces: null,
user_id: 4
},
{
firstname: 'Tony',
lastname: 'Santiago',
numberofplaces: null,
user_id: 2
},
{
firstname: 'Scully',
lastname: 'Smith',
numberofplaces: null,
user_id: 5
}
]
The function that I am using to render the page is
<% userlist.forEach(function(songlist) { %>
<ul class="list-group list-group-numbered">
<input type="checkbox" name=<%= userlist.firstname %>
<li class="list-group-item"><%= userlist['firstname'] %>, By: <%= userlist['lastname' ]%> </li>
</ul>
<% }); %>
Lastly this is the API route
app.get('/process_form', function(req, res){
// create a variable to hold the username parsed from the request body
// Now we will use the token wiht the name that the user entered
// For this we will use the axios method to return the result
axios.get('http://127.0.0.1:5000/api/getuser')
.then((response)=>{
var userlist = response.data.results;
console.log(userlist);
res.render('pages/letseat', {
userlist: userlist
});
Please give me some guidance I've been stuck on this for 3 hours!!!
You are trying to access a property that doesn't exist and returning that caused it to be undefined.
var userlist = response.data.results
// ^^^^^^^
response.data is already an array you wanted. So you gotta change to
var userlist = response.data

Display to client only if collection exists on mongoDB Node JS

I have this schema model defined on Mongoose:
var mongoose = require("mongoose");
var IngredientSchema = new mongoose.Schema({
name:String,
number:Number,
exist:Boolean,
photoName:String
})
module.exports = mongoose.model("Ingredient", IngredientSchema);
And I want to display on a web page a different result depending on whether there is an Ingredient already created on database or not.
Here's what I tried so far (but it doesn't work):
<!-- Check if inventory is empty or not, and display accordingly -->
<% if ( ! ingredients) { %>
<p>Add you first ingredient to the inventory !!</p>
<% } else { %>
<% ingredients.forEach(function(ingredient) { %>
...
...
And here's my route:
// Index route
app.get("/inventory", function(req, res) {
Ingredient.find({}, function(err, allIngredients) {
if (err) {
console.log(err);
} else {
res.render("inventory", { ingredients:allIngredients });
}
})
})
Thank you very much for your help.
Just check the length of ingredients array:
<!-- Check if inventory is empty or not, and display accordingly -->
<% if (!ingredients.length) { %>
<p>Add you first ingredient to the inventory !!</p>
<% } else { %>
<% ingredients.forEach(function(ingredient) { %>
...
...

Node.js cant log Class model data from Student model

I am having an issue here. I currently am making a school directory using node.js and MongoDB. I am in an app.post request and for some reason I can't get the name of the class being linked to the student to log to the console, but createdClass.name will print...
Here is the code...
app.post("/students/:id", function(req, res){
Student.findById(req.params.id, function(err, foundStudent){
if(err){
console.log(err);
} else {
Class.create(req.body.class, function(err, createdClass){
if(err){
console.log(err);
} else {
createdClass.student.id = foundStudent._id;
createdClass.student.name = foundStudent.name;
console.log(createdClass);
createdClass.save();
foundStudent.classes.push(createdClass);
console.log(foundStudent.classes[0].name);
foundStudent.save();
}
});
}
});
res.redirect("/students/" + req.params.id);
});
Also, here are my models...
STUDENT:
var mongoose = require("mongoose");
var studentSchema = new mongoose.Schema (
{
name: String,
classes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Class"
}
],
grades: Array
}
);
module.exports = mongoose.model("Student", studentSchema);
CLASS:
var mongoose = require("mongoose");
var classSchema = new mongoose.Schema (
{
name: String,
student:
{
id:
{
type: mongoose.Schema.Types.ObjectId,
ref: "Student"
},
name: String
}
}
);
module.exports = mongoose.model("Class", classSchema);
Thank you in advance and please do let me know if there is anything I can add to make this easier to read.
Here is the page making the post request...
<div>
<h1>Student Profile</h1>
<h2>Name: <%=student.name%></h2>
<div>
<h3>Classes:
<form action="/students/<%= student._id %>" method="POST">
<%if(student.classes.length === 0){%>
<p>No classes linked to profile, please add class..</p>
<input type="text" name="class[name]" placeholder="Class name">
<% } else { %>
<% student.classes.forEach(function(course){ %>
<li><%= course.name %></li>
<% }); %>
<% } %>
</form>
</h3>
</div>
</div>
Class is a reserved word and can't be used for a variable

Find MongoDB document from id posted as hidden input

How can I find the document matching the ID being posted in a hidden input?
Here is my schema:
var MessageSchema = Schema({
name: {type: String, required: true},
message: {type: String, required: true},
replies: [{ type: Schema.Types.ObjectId, ref: 'Comment' }]
}, {timestamps: true});
Here is my form:
<% for(var i=0; i<messages.length; i++) { %>
<form action="/comment/create" method="post">
<label>Name: </label>
<input type="name" name="name">
<label>Comment: </label>
<input type="text" name="comment">
<input type="hidden" name="replyTo" value=<%= messages[i]['_id']%> >
<button>Reply</button>
</form>
<% } %>
And my post route is a mess so at this point I just want to know how to find the dang message.
app.post('/comment/create', function(req, res) {
console.log(req.body.replyTo);
var message = Message.find({ _id: req.body.replyTo });
console.log(message);
res.redirect('/');
})
console.log(req.body.replyTo) returns the id 59022ff22951ce73ed9bb773.
console.log(message) returns undefined.
The call to Messages.find is asynchronous, and therefore will not provide a proper value when assigning it's result to the variable message. You need to handle this either with a callback or a Promise:
As a callback
Message.find({ _id: req.body.replyTo }, (err, res) => {
console.log(res); // message
});
As a Promise
Message.find({ _id: req.body.replyTo })
.then((res) => {
console.log(res); // message
})
.catch((err) => {
// ...
});

how to use app.locals inside app.get in express and parse

I am working on a parse application using express. I have an index file which shows the same information to the logged in users and public users except a login to public users and logout to logged in users. I am using app.locals to store a flag and logged-in user name but some how they are not getting stored.
My code for app.js is
// The homepage renders differently depending on whether user is logged in.
app.get('/', function(req, res) {
if(Parse.User.current()){
Parse.User.current().fetch().then(function(user) {
// Render the user profile information (e.g. email, phone, etc).
name = user.get('username');
});
app.locals({flag :true,name:name});
}else{
app.locals({flag:false, name:''});
}
// Render a public welcome page, with a link to the '/' endpoint.
var ProfessionalUsers = Parse.Object.extend("User");
var query = new Parse.Query(ProfessionalUsers);
query.limit(50);
query.equalTo("usertype", "Professional");
query.find().then(function(profs) {
res.render('index', {
title: "Popular Experts",
profs: profs,
});
});
});
The code I have written in index
<div class='navigation'>
<ul class='navigation-ul'>
<li><a href='/' class='search' id='searchLink' >Search</a></li>
<% if(flag){ %>
<li><a href='/dashboard' class='dashboard' id='dashboardLink' >Dashboard</a></li>
<% } %>
<li><a href='/howitworks' class='how-it-works' id='howItWorksLink'>How it Works</a></li>
<li><a href='/testimonials' class='testimonials' id='testimonialsLink' >Testimonials</a></li>
<li><a href='/faqs' class='faqs' id='faqsLink'>FAQs</a></li>
<% if(flag){ %>
<li><a href='/logout' class='logout' id='logoutLink'>Logout<span class='username'>(<%= name ? name : '' %>)</span></a></li>
<% }else{ %>
<li><a href='/login' class='login-signup' id='navLoginSignupLink'>Login/Signup</a></li>
<% } %>
</ul>
</div>
the code to show professionals
<p><%= title %></p>
<div class='professionals'>
<% for(var i=0;i<profs.length;i++) { %>
<div class='professional'>
<div class='picture-space' onclick = 'location.href = "/user/<%= profs[i].id %>"' style='cursor:pointer'>
<img src='images/default.jpg'/>
</div>
<div class='name-space'><%= profs[i].attributes.username %></div>
<div class='service-space'><%= profs[i].attributes.servicetype %></div>
<div class='linkedin-space'><a href='http://<%= profs[i].attributes.linkedin %>' target='_blank'>Linkedin Profile</a></div>
</div>
<% } %>
</div>
EDIT:
This is what I have done to fix this
// The homepage renders differently depending on whether user is logged in.
app.get('/', function(req, res) {
// Render a public welcome page, with a link to the '/' endpoint.
var ProfessionalUsers = Parse.Object.extend("User");
var query = new Parse.Query(ProfessionalUsers);
query.limit(50);
query.equalTo("usertype", "Professional");
query.find().then(function(profs) {
var user = Parse.User.current();
if(user){
user.fetch().then(function(user,error) {
res.render('index',{user:user.toJSON(),profs:profs,title:'Popular Experts'});
});
}else{
res.render('index', {
title: "Popular Experts",
profs: profs,
user:''
});
}
});
});
app.locals doesn't have access to the req, res objects. It is intended for non-dynamic data that doesn't change per request (like app-name, or something similar). I believe what you are after is res.locals (http://expressjs.com/api.html#res.locals)
I would suggest adding some middleware that does what you want.
You could load it just for your route. This will execute the middleware RIGHT before it executes the function you defined at that route:
function getUserInfo(req, res, next) {
var user_name = "adam"; //make some call here to get the user data
//make 'user_name' variable available in the view
res.locals.user_name = user_name;
next(); //go to the next 'middleware', which is the stuff you defined.
}
//add getUserInfo here as middleware that will run on the '/' route BEFORE your middleware runs. Yours will be executed when 'next()' is called from the middleware function.
app.get('/', getUserInfo, function(req, res) {

Categories