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 !
Related
Expense Tracker application : Nodejs, Mongodb
Trying to Create a function that will update only the passed fields from request inside an array of objects
Database Schema
const updateExpense = async (req, res) => {
try {
let db = mongo.getDb()
let { macro, micro, amount, note } = req.body;
let { username, id } = req.query
let expense = await db.collection("Expense").updateOne({ username: username, "expenses.expense_id": ObjectId(id) }, { $set: {
"expenses.$.macro": macro,
"expenses.$.micro": micro,
"expenses.$.amount": amount,
"expenses.$.note": note }
});
res.status(200).json({
message: "Expense Updated",
expense: expense
});
} catch (err) {
res.status(500).json({
message: err.message
});
}
}
The above function is replacing all other fields with null
If the user is passing only the micro field, then the other fields should remain the same and only the micro field should change and other fields should not change.
Need A MongoDB Query which will only change what is required based on the data passed in req
I think you must first fetch from the database with findOne then update that fields set in req.body, something like this:
const updateExpense = async (req, res) => {
try {
let db = mongo.getDb()
let { macro, micro, amount, note } = req.body;
let { username, id } = req.query
let expense = await db.collection("Expense").findOne({ username: username });
let special_ex = expense.expenses.find(ex => ex.expense_id === ObjectId(id);
special_ex.macro = macro ? macro : special_ex.macro;
special_ex.micro = micro ? micro : special_ex.micro;
/*
and so on ...
*/
await expense.update();
res.status(200).json({
message: "Expense Updated",
expense: expense
});
} catch (err) {
res.status(500).json({
message: err.message
});
}
}
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 have the following mongoose schema:
user = {
"userId" : "myId",
"connections":
[{
"dateConnectedUnix": 1334567891,
"isActive": true
}, {
"dateConnectedUnix": 1334567893,
"isActive": false
}]
}
I would like to delete the second item in the connections array, to get the following:
user = {
"userId" : "myId",
"connections":
[{
"dateConnectedUnix": 1334567893,
"isActive": false
}]
}
The following code does the job as expected:
userAccounts.update(
{ 'connections.isActive': false },
{ $pull: { 'connections.isActive':false }},
function (err, val) {
console.log(val)
}
);
But, I need to delete based on ObjectId. And the following goes does not work:
userAccounts.update(
{ 'connections._id': '1234-someId-6789' },
{ $pull: { 'connections._id': '1234-someId-6789' } },
function (err, val) {
console.log(val)
}
);
Any suggestions? I have been banging my head against the screen (aka Google, Stackoverflow, ...) for hours and have had no luck.
It seems that the above code would not work. It should not even have worked for the first example I gave.
In the end I was supported by this answer here: MongoDB, remove object from array
Here is my working code:
userAccounts.update(
{ userId: usr.userId },
{
$pull: {
connections: { _id : connId }
}
},
{ safe: true },
function removeConnectionsCB(err, obj) {
// ...
}
);
I have a document like
I have to delete address from address array
After searching lots on internet I found the solution
Customer.findOneAndUpdate(query, {$pull: {address: addressId}}, (err, data) => {
if (err) {
return res.status(500).json({ error: 'error in deleting address' });
}
res.json(data);
});
user: {
_id: ObjectId('5ccf3fa47a8f8b12b0dce204'),
name: 'Test',
posts: [
ObjectId("5cd07ee05c08f51af8d23b64"),
ObjectId("5cd07ee05c08f51af8d23c52")
]
}
Remove a single post from posts array
user.posts.pull("5cd07ee05c08f51af8d23b64");
user.save();
To use update with ObjectId, you should use ObjectId object instead of string representation :
var ObjectId = require('mongoose').Types.ObjectId;
userAccounts.update(
{ 'connections._id': new ObjectId('1234-someId-6789') },
{ $pull: { 'connections._id': new ObjectId('1234-someId-6789') } },
function (err,val) {
console.log(val)
}
);
use findByIdAndUpdate to remove an item from an array
You can do it in mongoose 5.4.x and above
const result = await User.findByIdAndUpdate(user_id, {
$pull: {
someArrayName: { _id: array_item_id }
}
}, { new: true });
The item from array will be removed based on provided property _id value
If you are using mongoose, no need to use the MongoDB stuff, I mean that's why we're using mongoose in the first place, right?
userAccounts.connections.pull({ _id: '1234-someId-6789'});
await userAccounts.save();
mongoose: 4.11.11
What have worked for me is the following syntax:
const removeTansactionFromUser = (userId, connectionId) => {
return User.findByIdAndUpdate(userId, { $pull: { "connections": connectionId} }, {'new': true} );
};
Mongoose support id in string format or ObjectId format.
Tip: new ObjectId(stringId) to switch from string to ObjectId
In mongoose 5.8.11, this $pull: { ... } didn't work for me, so far not sure why. So I overcame it in my controller this way:
exports.removePost = async (req, res, next) => {
const postId = req.params.postId;
try {
const foundPost = await Post.findById(postId);
const foundUser = await User.findById(req.userId);
if (!foundPost || !foundUser) {
const err = new Error(
'Could not find post / user.',
);
err.statusCode = 404;
throw err;
}
// delete post from posts collection:
await Post.findByIdAndRemove(postId);
// also delete that post from posts array of id's in user's collection:
foundUser.posts.pull({ _id: postId });
await foundUser.save();
res.status(200).json({ message: 'Deleted post.' });
} catch (err) {
// ...
}
};
I'm trying to update an existing record with Mongoose. The insert is OK but not the update.
Here is my snippet:
app.post('/submit', function(req, res) {
var my_visit = new models.visits({
date: req.body.visit_date,
type: req.body.visit_type,
agency: req.body.visit_agency,
city: req.body.visit_city,
url: req.body.visit_url,
note: req.body.visit_note
});
// INSERT
if(req.body.id == 0) {
my_visit.save(function(err) {
if(err) { throw err; }
console.log('added visit');
res.redirect('/');
});
} else { // UPDATE
var upsertData = my_visit.toObject();
console.log(req.body.id); // OK
models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
if(err) { throw err; }
console.log('updated visit: '+ req.body.id);
res.redirect('/');
});
}
})
The response is Mod on _id is not allowed.
I just want to update the line such as WHERE id = id in MySQL. I didn't find the right syntax.
According to this question and this other one, the Mod on _id is not allowed occurs when one tries to update an object based on its id without deleting it first.
I also found this github issue which tries to explain a solution. It explicitly states:
Be careful to not use an existing model instance for the update clause
(this won't work and can cause weird behavior like infinite loops).
Also, ensure that the update clause does not have an _id property,
which causes Mongo to return a "Mod on _id not allowed" error.
The solution, it seems, is to do the following:
var upsertData = my_visit.toObject();
console.log(req.body.id); // OK
delete upsertData._id;
models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
if(err) { throw err; }
//...
}
On a side note, you can probably rewrite your route to do both the create and update without the if-else clause. update() takes an extra option upsert, which, according to the docs:
upsert (boolean) whether to create the doc if it doesn't match (false)
Here is my solution:
routes/router.js
router.patch('/user/:id', userController.updateUser)
exports.updateUser = async(req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ['name', 'email', 'password', 'age']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send('Invalid updates!')
}
try {
const user = await UserModel.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })
if (!user) {
return res.status(404).send()
}
res.status(201).send(user)
} catch (error) {
res.status(400).send(error)
}
}