I'm making a Forum application with my first Node Express Mongo API. Posts have an array of comments, and I am trying to delete a comment, based in it's id.
My method returns without errors, but the comment is never deleted.
Deleting method:
export const deleteComment = async (req, res) => {
const commentId = req.body._id
const post = await Post.findById(req.params.id)
const _id = post.id
try {
await Post.updateOne(
{ _id },
{
$pull:
{
comments: { _id: commentId }
}
}
)
res.status(200).json({ message: 'Success' })
} catch (error) {
res.status(400).json({ error: error.message })
}
}
The model looks like the following:
Previously, when using the updateOne method, it for some reason had issues finding the id of the model to update, but I have now used the same formula as before, so I don't see that as being an issue.
Any guesses of what I can do to fix this?
Related
I have saved my data in MongoDB using mongoose. Now I want to get the 'quantity' field in cart and increment by 1.
Note : If you have better way to do it, Please help.
here is how the MongoDB Atlas collection looks like
Here is how iam doing it :
const User = require("../models/User");
exports.updateQuantity = async (req, res) => {
try {
const { userId } = req.body;
if (!userId) {
res.json("All fields are required");
}
let result = await User.findByIdAndUpdate(
userId,
{
$inc: {
"cart.$[inner].newProduct.quantity": 1,
},
},
{
new: true,
}
);
res.send({
success: true,
message: "Product has been incremented",
result: result,
});
} catch (error) {
console.log(error);
return res.status(500).json({
success: false,
message: "Something went wrong",
});
}
};
Getting this error:
You doing good, actually you need to get the right object since you are working in an array.
I see the cart could have multiple product so you need to find the right product by its id
Pass to your query another parameter to match the right object like this :
await User.findByIdAndUpdate({_id : userId, "cart.userId" : userId, "cart.newProduct._id" : productId })
Than you can increment by adding
$inc: {
"cart.newProduct.quantity": 1,
},
Maybe you won't have to put the "cart.userId" : userId in the filter if there aren't other userId
Hope it works !
I have been trying to access a collection that was dynamically created in the database through {$out: "Accepted"} in nodejs using mongoose. the collection was successfully created.
from the controller:
exports.accepted = async (req, res, next)=>{
await Pupil.aggregate([{$match: {status: "Accepted"}}, {$out: "Accepted" }])
**Accepted.find({}).then(result=>{
res.render('home/accepted', {results: result, pageTitle: 'accepted page'})
}).catch(error=>{
console.log(error)*emphasized text*
});**
}
I want to retrieve the documents in that 'Accepted' collection and render them to the ejs file.
the error message is:
Accepted.find({}).then(result=>{
^
ReferenceError: Accepted is not defined at exports.accepted...
can someone please help me out?
Thanks!
Welcome to StackOverflow #Jerevick
There are two possible cases here:
Case 1 - You don't need to write to a new collection
You just want to find documents of accepted pupils and render them in the EJS template, in which case:
A) You don't need to write your documents into a new collection, you can just get them from the result and pass them to your template.
exports.accepted = async (req, res, next) => {
try {
const result = await Pupil.aggregate([{ $match: { status: 'Accepted' } }]);
res.render('home/accepted', { results: result, pageTitle: 'accepted page' });
} catch (err) {
console.log(err);
}
};
B) You don't even need the aggregation framework, you can just do a simple find:
exports.accepted = async (req, res, next) => {
try {
const result = await Pupil.find({ status: 'Accepted' });
res.render('home/accepted', { results: result, pageTitle: 'accepted page' });
} catch (err) {
console.log(err);
}
};
Case 2 - you need to write to a new collection, and your example was just to simplify
If that's the case, it's important to emphasize the difference between mongoose and MongoDB. Mongoose is a wrapper around the native MongoDB driver to help with casting, and provide a nicer API.
When you add a new collection to the database using the $out stage, the mongoose isn't aware of it and it doesn't assign a model for it and has no idea what kind of data live there, in which case you would need to bypass mongoose and use the native MongoDB driver directly.
I highly advise against this approach, since you'd be giving up all the convenience mongoose provides, don't take this approach unless you really know what you're doing, there's probably a better solution than using the native driver directly.
exports.accepted = async (req, res, next) => {
try {
await Pupil.aggregate([{ $match: { status: 'Accepted' } }, { $out: 'Accepted' }]);
const acceptedCollection = mongoose.connection.collection('Accepted');
const result = await acceptedCollection.find({}).toArray();
res.render('home/accepted', { results: result, pageTitle: 'accepted page' });
} catch (err) {
console.log(err);
}
};
Here's a full reproduction script you can play with:
65209755.js
'use strict';
const mongoose = require('mongoose');
const { Schema } = mongoose;
const assert = require('assert');
run().catch(console.error);
async function run () {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true
});
await mongoose.connection.dropDatabase();
const studentSchema = new Schema({
name: String,
status: String
});
const User = mongoose.model('User', studentSchema);
await User.insertMany([
{ name: 'Hafez1', status: 'Accepted' },
{ name: 'Hafez2', status: 'Accepted' },
{ name: 'Hafez3', status: 'Accepted' },
{ name: 'Hafez4', status: 'Rejected' },
{ name: 'Hafez5', status: 'Rejected' }
]);
await User.aggregate([
{ $match: { status: 'Accepted' } },
{ $out: 'acceptedstudents' }
]);
const db = mongoose.connection;
const acceptedStudents = await db.collection('acceptedstudents').find({}).toArray();
assert.deepStrictEqual(
acceptedStudents.map(student => student.name),
['Hafez1', 'Hafez2', 'Hafez3']
);
console.log('All assertions passed.');
}
Output
$ node 65209755.js
All assertions passed.
GoodDay Experts,
I've tried following code but it did not work, and it gives me null value.. maybe my routes are wrong but basically it works the way on other routes... and here is my backend for delete case: manage.js/actions
export const removeRecipient = (payload) => async (dispatch) => {
try {
const res = await axios.delete(
`${_config.MAT_URL}/api/1/customer/delete`,
payload
);
dispatch({
type: DELETE_CUSTOMER,
payload: res.data,
});
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { err },
});
}
};
and for my routes which is the mongoose query for findOneAndDelete, under customer.js :
router.delete("/delete", (req, res) => {
Customer.findOneAndDelete({ _id: req.params.id }, (err, Customer) => {
if (!err) {
res.json({ msg: "customer deleted", deleted: Customer });
} else {
console.log("Error removing :" + err);
}
});
});
And for the front end im using "AiOutlineDelete" which was coded as :
const handleDelete = (id) => {
console.log('delete')
removeRecipient(id)
}
<a
id={`delete-${rowIndex}`}
className="anchor-action-delete"
href="#foo"
onClick={(e) => {
e.preventDefault();
handleDelete(row);
}}>
thanks have a great day
There are 2 problems in your code:
req.params.id is meant for urls of the form /delete/:id which is obviously not your route, you should change it to req.query.id instead which matches query parameters in the url such as /delete?id=123.
The default type of _id is ObjectId, under the assumption you did not change this you need to cast your req.query.id which is type string to ObjectId.
It looks like you're using mongoose so here's mongoose syntax:
const mongoose = require("mongoose");
router.delete("/delete", (req, res) => {
Customer.findOneAndDelete({ _id: new mongoose.Types.ObjectId(req.query.id) }, (err, Customer) => {
if (!err) {
res.json({ msg: "customer deleted", deleted: Customer });
} else {
console.log("Error removing :" + err);
}
});
});
For nodejs native Mongo package:
import {ObjectId} from "mongodb";
...
new ObjectId(req.query.id)
I dont see you sent the id to the backend but you are trying to retrieve it from req.params.id try passing the id like "delete/:id" at the end of the link and specify this in the routes aswell.
if that doesnt fix try the below code this for routes
if nothing works check this, In the component you need to send the id(object id) but i see "row" what is the value of row? if the row value is not the id in the database then it wont delete. if this your issue try inspecting the code by keeping breakpoints or write a console.log() to check the value of "row" .
try {
const removedProject = await Customer.remove({
_id: req.params.id
})
res.json(removedProject)
} catch (err) {
res.json({
message: err
})
}
I have this following Mongoose User Schema:
postCreated:{
type: Array,
default: []
}
which contains an Array of Object of Posts belong to that user. I plan to do the following: When I delete a particular post, I pass the id of that post and the username of the user that created to the back-end and hope that it would remove the post from both Post schema and postCreated of a user that it belongs to
server.del('/posts',(req,res,next)=>{
const {id,username} = req.body;
User.findOne({username}).then(user => {
console.log(user.postCreated)
user.postCreated.filter(post => {
post._id !== id;
});
console.log(user.postCreated)
});
Posts.findOneAndRemove({_id: id}).then((post) => {
if(!post){
return next(new errors.NotFoundError('Post not found'));
}
res.send(post);
})
.catch((e) => {
return next(new errors.BadRequestError(e.message));
});
});
However, the post only got removed from the Post Model, and not from postCreated of User Model, meaning that the user.postCreated.filter did not work.
I have tried the following, thanks to Jack, but seems like it did not solve the issue:
User.update(
{ username },
{ $pull: { postCreated: {_id: id} } },
{ multi: true }
);
Is there any way that I could fix this?
I would really appreciate any help.
If you want to do it the way you were doing you need to store back your postCreated array into it self and then save the user:
User.findOne({username}).then(user => {
console.log(user.postCreated)
user.postCreated = user.postCreated.filter(post => {
post._id !== id;
});
console.log(user.postCreated);
user.save();
});
But the best way is findOneAndUpdate if you need the user object later on.
You can use mongoose $pull
Use: https://docs.mongodb.com/manual/reference/operator/update/pull/
User.update(
{ username },
{ $pull: { postCreated: id } },
{ multi: true }
);
This should solve your query.
I am saving a document in mongodb using mongoose and I wanna send data to the user by excluding some fields like _id.
router.post('/', async (req, res) => { // create category with an item
try {
const category = new Category({
name: req.body.name,
icon_url: req.body.icon_url,
items_quantity: req.body.items.length
})
const data = await category.save();
res.send(data);
} catch (err) {
debug(err.message);
}
})
I want to exclude _id property. I have searched for this but couldn't find the solution. someone suggested to use Node Package underscore but how to do it without it. Someone suggested about lean() and I couldn't understand, how to use it in my case.
To do that, I just delete this field before sending to client side like this :
router.post('/', async (req, res) => { // create category with an item
try {
const category = new Category({
name: req.body.name,
icon_url: req.body.icon_url,
items_quantity: req.body.items.length
})
const data = await category.save();
data._id = null;
res.send(data);
} catch (err) {
debug(err.message);
}
})
Then _id field isn't sent.
Hope it helps.
You can use this bro.
I hope it helps :)
let obj = {
_id: '475947598475947957jdhfjkdhjkghdfkjhgjkhdyfer9t8',
name: 'John Doe'
}
delete obj['_id'];
console.log(obj);