Error while pushing data into nested array of mongoose - node.js

I am trying to push data in the treatment arrray which is nested in files array.
schema of patient:
var treatmentSchema = new Schema({
prescription:{
type : String,
},
record: {
data: Buffer,
contentType: String
}
});
var FileSchema = new Schema({
drName : {
type : String,
requried : true
},
desease :{
type:String,
requried:true
},
treatment : [treatmentSchema]
},{
timestamps : true
});
var patientSchema = new Schema({
pat_no:{
type:Number
},
username:{
type : String,
requried : true,
unique : true
},
DOB : {
type:Date
}
,
password:{
type : String,
requried : true,
unique : true
},
name : {
type : String,
requried : true
},
email:{
type : String,
requried : true
},
aadhar : {
type : String,
requried : true,
unique : true
},
image: {
data: Buffer,
contentType: String
},
nomeneeAadhar:{
type : String,
requried : true,
},
files : [FileSchema]
};
code:
Doctor.findById(req.cookies.user)
.then((doctor)=>{
var image={}
if(req.files)
{
image={
data: new Buffer(req.files.record.data,'base64'),
ctType: req.files.record.name.split('.').pop()
}
}
Patient.updateOne({"_id" :req.params.patID },
{
"$push": {
"files.$[t].treatment":{
"prescription":req.body.comment,
"record":image
}
}
},
{ arrayFilters: [ { "t.drname": doctor.name , "t.desease":req.body.dise } ]},
function(err, result){
if(err){
console.log(err)
}else if(!result){
//update not success
console.log("no success")
}else{
console.log(result)
console.log("success")
}
})
.then((doc)=>{
res.send(doc)
})
})
result:
{"n":1,"nModified":0,"ok":1}
I tried this method as well:
Doctor.findById(req.cookies.user)
.then((doctor)=>{
var image={}
if(req.files)
{
image={
data: new Buffer(req.files.record.data,'base64'),
ctType: req.files.record.name.split('.').pop()
}
}
Patient.updateOne(
{
_id:req.params.id,
"files.drName" :doctor.name,
"files.desease" :req.body.dise
},
{
$push :{
"files.$.treatment":{
"prescription":req.body.comment,
"record":image
}
}
}
)
.then((doc)=>{
res.send(doc)
})
})
DB connection:
var connect = mongoose.connect('mongodb://localhost:27017/doctor', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then((db) => {
console.log("Database Connected Successfully");
})
.catch((err) => {
var err = new Error("Error in Database connectivity");
return next(err);
})
Data not get updated in db.
please help!!
thank you!

Related

I want to pass array object inside array subdocument in mongoose

Here is my Schema
I am trying to add replies array inside answers array. If someone answers a question and if someone wants to reply on the given answer
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const questionSchema = new mongoose.Schema(
{
postedBy: {
type: ObjectId,
required: true,
ref: "User",
},
question: {
type: String,
required: true,
},
photo: {
data: String,
required: false,
},
answers: [
{
userId: { type: ObjectId, ref: "User" },
answerType: {
data: String,
required: false,
},
answer: String,
replies: [
{
userId: { type: ObjectId, ref: "User" },
reply: String,
replyType: {
data: String,
required: false,
},
},
],
},
],
questionType: {
data: String,
required: false,
},
createdAt: {
type: Date,
required: true,
default: Date.now,
},
},
{ timeStamps: true }
);
module.exports = mongoose.model("Question", questionSchema);
Here is my Controller method
exports.postReply = (req, res) => {
const reply = req.body.reply || "";
const userId = req.user._id || "";
const answerId = req.body.answerId || "";
Question.findByIdAndUpdate(
{ _id: answerId },
({ $push: { answers: { answer: { replies: { reply, userId } } } } },
{ new: true }),
(err, newReply) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
} else {
res.json({
msg: "Reply posted successfully",
newReply,
});
}
}
);
};
I feel I am going wrong on the findOneAndUpdate method. I am getting no error on the console but newReply comes null. Any help will be appreciated.
I would suggest you using the $addToSet instead of the $push operator as you are adding a document to the array. (see: https://docs.mongodb.com/manual/reference/operator/update/addToSet/).
If you want to add more than one document to the array, refer also to the $each operator together with $addToSet.
So your coding can look similiar to this (note: the variable 'yourDocument' is the document you want to add):
Question.findByIdAndUpdate(
{ _id: answerId },
{ $addToSet: { answers: yourDocument } },
{ new: true },
(err, newReply) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
} else {
res.json({
msg: "Reply posted successfully",
newReply,
});
}
}
);
};
The problem is clearly the parentesis around
({ $push: { answers: { answer: { replies: { reply, userId } } } } }, { new: true })
Doing this console.log( ({a:1}, {b:2}) ); will log {b: 2} which means you are doing this
Question.findByIdAndUpdate( { _id: answerId }, { new: true }, (err, newReply) => {
So remove the parentesis and you should be good
Question.findByIdAndUpdate(
{ _id: answerId },
{ $push: { answers: { answer: { replies: { reply, userId } } } } },
{ new: true },
(err, newReply) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
} else {
res.json({
msg: "Reply posted successfully",
newReply,
});
}
}
);

How to Delete Comment from Post on Node, express and Mongoose and Ajax

Please i need help on how to delete a single comment from a Post. when i click delete it return 500 error. some of the things that are confusing me here is, if i pass both post and comment ids on the link, how will i tell Ajax that this one is for post and this one is for comment.
Here is my posts schema
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
from: {
type: String,
required: true
},
createdAt: {
required: true,
default: Date.now
},
postImage: {
type: String,
require: true
},
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }]
})
here is my ajax from main.js file.
/deleting comment with Ajax
$(document).ready(function() {
$('.delete-comment').on('click', function(e) {
const $target = $(e.target);
const id = $target.attr('data-id');
$.ajax({
type: 'DELETE',
url: '/posts/comments/'+id,
success: function(response) {
window.location.href='/posts';
},
error: function(err){
console.log(err);
}
});
});
});
my routes/comments
//Delete comment inside a post
router.delete( '/comments/:id', function( req, res ){
const post = Post.findOne({_id: req.params.postId});
const ObjectId = mongoose.Types.ObjectId;
let query = {_id:new ObjectId(req.params.id)}
console.log(query)
post.comments.delete(query, function(err) {
if(err){
console.log(err);
}
res.send('Success');
});
})
my views/index.ejs
//Comments and link
<% const counter = post.comments.length >= 2 ? "Comments" : "Comment"; %>
<button class="show-comments"><%= post.comments.length + " " + counter + "" %></button>
<% %>
<div class="postcomments" ><% post.comments.forEach(item => { %>
<ul >
<li><%= item.description %></li>
<a class="delete-comment" href="#" data-id="<%=item._id%>">Delete</a>
</ul>
<% });%>
my app.js
//use route from app.js
var commentRouter = require('./routes/comments');
app.use('/posts', commentRouter);
here is what is being returned on my terminal
DELETE /posts/comments/5e8ad7121277855e656b3379 500 5.395 ms - 3698
You need to know both the postId and the commentId to be able to delete the comment from posts collection. Also it would be good to delete the comment inside the comments collection.
So change your delete route to include postId and commentId as req.params.
You can delete a comment from posts using the findByIdAndUpdate method and $pull operator.
router.delete("/comments/:postId/:commentId", async function (req, res) {
try {
const post = await Post.findByIdAndUpdate(
req.params.postId,
{
$pull: { comments: req.params.commentId },
},
{ new: true }
);
if (!post) {
return res.status(400).send("Post not found");
}
await Comment.findByIdAndDelete(req.params.commentId);
res.send("Success");
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
TEST
Let's say we have this post document with 3 comments.
Posts:
{
"_id" : ObjectId("5e8b10c49ae619486094ed10"),
"comments" : [
ObjectId("5e8b104f9ae619486094ed0d"),
ObjectId("5e8b10599ae619486094ed0e"),
ObjectId("5e8b105e9ae619486094ed0f")
],
"title" : "Title",
"description" : "Description...",
"from" : "From",
"postImage" : "Post Image",
"createdAt" : ISODate("2020-04-06T14:21:40.884+03:00")
}
Comments:
{
"_id" : ObjectId("5e8b105e9ae619486094ed0f"),
"message" : "Comment 3"
},
{
"_id" : ObjectId("5e8b10599ae619486094ed0e"),
"message" : "Comment 2"
},
{
"_id" : ObjectId("5e8b104f9ae619486094ed0d"),
"message" : "Comment 1"
}
If we want to delete the comment with _id:5e8b10599ae619486094ed0e, we need to send a DELETE request to our route using url like this:
http://localhost:3000/posts/comments/5e8b10c49ae619486094ed10/5e8b10599ae619486094ed0e
5e8b10c49ae619486094ed10 is the postId, 5e8b10599ae619486094ed0e is the commentId.
Result will be like this:
Posts:
{
"_id" : ObjectId("5e8b10c49ae619486094ed10"),
"comments" : [
ObjectId("5e8b104f9ae619486094ed0d"),
ObjectId("5e8b105e9ae619486094ed0f")
],
"title" : "Title",
"description" : "Description...",
"from" : "From",
"postImage" : "Post Image",
"createdAt" : ISODate("2020-04-06T14:21:40.884+03:00")
}
Comments:
{
"_id" : ObjectId("5e8b105e9ae619486094ed0f"),
"message" : "Comment 3"
},
{
"_id" : ObjectId("5e8b104f9ae619486094ed0d"),
"message" : "Comment 1"
}
Your nodejs/express route contains this code. Maybe it should do more with possible errors: specifically, pass the error to the next() function that's the third parameter of any route handler.
post.comments.delete(query, function(err) {
if(err){
console.log(err)
return next(err)
}
res.send('Success')
});
Passing an error value to next() should deliver the error message to the user. And, you have the same message showing up on your server's console.log. So if the error is from there you should learn more about it.
I am facing the same problem Except that before erasing the post, I want to make sure that the user deleting the post is the creator of the same post. My data set is a little bit different.
import mongoose from 'mongoose'
const postSchema = mongoose.Schema(
{
title: {
type: String,
required: true,
},
comment: { type: String, required: true },
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
imagePost: { type: String, required: true },
},
{
timestamps: true,
}
)
const stationSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
nameUnit: {
type: String,
required: true,
},
typeOfPoint: { type: String },
image: {
type: String,
required: true,
},
lat: {
type: Number,
required: true,
},
long: {
type: Number,
required: true,
},
// Base
nameBase: { type: String, required: true },
element: {
type: String,
required: true,
},
baseCommanderInfo: { type: String },
aboutBaseInfo: { type: String },
// Unit
unitSuperviserInfo: { type: String },
unitCommanderInfo: { type: String },
unitInfo: { type: String },
taskInfo: { type: String },
benefitInfo: { type: String },
// address
country: { type: String },
province: { type: String },
town: { type: String },
adresse: { type: String },
postalCode: { type: String },
posts: [postSchema],
},
{
timestamps: true,
}
)
const Station = mongoose.model('Station', stationSchema)
export default Station
NodeControler
const removeStationPost = asyncHandler(async (req, res) => {
const stationId = req.params.id
const postId = req.params.idPost
const userId = req.user._id
console.log(stationId)
console.log(postId)
console.log(userId)
const station = await Station.findById(stationId)
if (station) {
station.posts.pull(postId)
await station.save()
res.status(201).json({ message: 'Post removed' })
} else {
res.status(404)
throw new Error('Post not found')
}
})
So now everybody can delete anybody else post with Postman

how to use Mongoose to (add to , update,delete) Nested documents

I am a fresh mongoose user and I have a small exercise I have this schema
`var BusinessSchema = mongoose.Schema({
personal_email: { type: String, required: true, unique: true },
business_name: { type: String, required: true, unique: true },
business_emails: [{ email: String, Description: String }],
business_logo: { data: Buffer, contentType: String },
//Business Services
services: [{
service_name: { type:String,required:true},
service_price: Number,
promotion_offer : Number,
service_rating : [{Clinet_username:String ,rating : Number}],
service_reviews : [{Clinet_username:String ,review : String}],
type_flag : Boolean,
available_flag : Boolean
}]
});`
what I want to do is to update or add new service or delete rating using mongoose
business.update({// something here to update service_rating },function(err,found_business)
{
}); business.update({// something here to add new service_rating },function(err,found_business)
{
}); business.update({// something here to delete service_rating },function(err,found_business)
{
});
var where_clause = { /* your where clause */ };
var service_rating = {"username", 5};
to add :
business.update(where_clause, {
'$addToSet' : {
services.service_rating : service_rating
}
}, callback);
to delete :
business.update(where_clause, {
'$pull' : {
services.service_rating : service_rating
}
}, callback);
to update :
var other_where = {services.service_rating : {"user", 5}}; // your where clause
business.update(other_where, {
'$set': {
'services.service_rating.Clinet_username' : 'newUser',
'services.service_rating.rating' : 10
}
}, callback);

Failed to update single property by mongoose

Frist I have read and try the solution in the post of mongoose-and-partial-select-update.
However when I try to use the traditional style, query would work.
My schema:
var userSchema = mongoose.Schema({
local: {
email: {
type: String,
index: {
unique: true,
dropDups: true
}
},
password: String,
displayName: String,
avatar: {
type: String,
default: "./img/user.png"
},
role: {
type: String,
default: "student"
},
ask_history: [
{
question_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'questionAnswer'
},
favorite: Boolean,
ask_time: Date
}
],
interest: [String]
}
})
Working Update function:
User.findById(id, function(err, User) {
if (err) {
throw done(err);
}
if (!User) {
return;
}
User.local.role = "admin";
User.save(function(err, updatedUser) {
if (err) {
throw err
} else {
//good
}
})
});
However if I do this:
User.update({_id : id},
{$set{
local:{role:"admin"}
}
},function(...){...}
});
Code above will overwrite user into:
{
_id : "...",
local: {
role : "admin"
}
}
I read that $ will make the update only changing property, where I did wrong?
The positional operator $ works with array of subdocuments.
In your case you have a single sub-document, so the following should work:
User.update({_id : id},
{ $set
{
"local.role": "admin"
}
}, function(...){...}
});

Dynamic validation in Mongoose

I have model, where car property is optional, but there is some property in car nested document, which should be required if User has car, like cartype : {required: true}, but when car is defined.
var UserSchema = new Schema({
email: {
type: 'String',
required: true
},
car: {
carType: {
// should be required if user have car
type: 'Number',
default: TransportType.Car
},
}
})
If there is no default value for carType, we can define one function hasCar to required of carType as below
var UserSchema = new Schema({
email: {
type: 'String',
required: true
},
car: {
carType: {
type: 'Number',
required: hasCar,
//default: TransportType.Car
},
}
});
function hasCar() {
return JSON.stringify(this.car) !== JSON.stringify({});//this.car; && Object.keys(this.car).length > 0;
}
With test codes
var u1 = new UUU({
email: 'test.user1#email.com'
});
u1.save(function(err) {
if (err)
console.log(err);
else
console.log('save u1 successfully');
});
var u2 = new UUU({
email: 'test.user1#email.com',
car: {carType: 23}
});
u2.save(function(err) {
if (err)
console.log(err);
else
console.log('save u2 successfully');
});
Result:
{ "_id" : ObjectId("56db9d21d3fb99340bcd113c"), "email" : "test.user1#email.com", "__v" : 0 }
{ "_id" : ObjectId("56db9d21d3fb99340bcd113d"), "email" : "test.user1#email.com", "car" : { "carType" : 23 }, "__v" : 0 }
However, if there is default value of carType, here maybe one workaround
var UserSchema = new Schema({
email: {
type: 'String',
required: true
},
car: {
carType: {
type: 'Number',
required: hasCar,
default: 1
},
}
});
function hasCar() {
if (JSON.stringify(this.car) === JSON.stringify({carType: 1})) {
this.car = {};
}
return JSON.stringify(this.car) === JSON.stringify({});
}
UserSchema.pre('save', function(next){
// if there is only default value of car, just remove this default carType from car
if (JSON.stringify(this.car) === JSON.stringify({carType: 1})) {
delete this.car;
}
next();
});
With the above test codes, results are
{ "_id" : ObjectId("56db9f73df8599420b7d258a"), "email" : "test.user1#email.com", "car" : null, "__v" : 0 }
{ "_id" : ObjectId("56db9f73df8599420b7d258b"), "email" : "test.user1#email.com", "car" : { "carType" : 23 }, "__v" : 0 }

Resources