let cart = req.body.params.cart // array of objects that needs to be updated if exists in db, if not upsert it.
let userid = req.body.params.uid
for (let i = 0; i < cart.length; i++) {
Cart.updateOne({ user: userid, 'cart.product': cart[i].product._id },
{
$set: {
'cart.$.quantity': cart[i].quantity
}
},
{ upsert: true }// works without this line of code, updates the objects if exists
)
}
my cart model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CartSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
cart: [{
product: {
type: Schema.Types.ObjectId,
ref: 'productlist'
},
quantity: {
type: Number
},
date: {
type: Date,
default: Date.now
}
}]
})
module.exports = Cart = mongoose.model('cart', CartSchema)
I'm trying to update a users shopping cart with new items that are in the cart array. I need to check if product exists, if yes update quantity, if not push it in to user's cart. Somehow it doesnt work with $upsert. without $upsert document gets updated if object id exists in the user's cart.
Working version with tons of clutter. I feel like there is a better way of doing it like the one I was trying to do above. I would appriceate any help, reducing clutter here.
Cart.find({ user: req.body.params.uid })
.then(userCart => {
if (userCart[0].cart.length === 0) {
for (let i = 0; i < cart.length; i++) {
Cart.updateOne({ user: req.body.params.uid }, {
$push: {
cart: {
product: cart[i].product._id,
quantity: cart[i].quantity
}
}
}).catch(err => console.log(err))
}
}
else {
cart.reduce((acc, element) => {
let index = userCart[0].cart.findIndex(val => val.product._id == element.product._id)
if (index !== -1) {
Cart.findOneAndUpdate({ user: req.body.params.uid, 'cart.product': element.product._id },
{
$set: {
'cart.$.quantity': element.quantity
}
},
{ new: true }
).then(a => console.log(a))
}
else {
Cart.updateOne({ user: req.body.params.uid }, {
$push: {
cart: {
product: element.product._id,
quantity: element.quantity
}
}
}).catch(err => console.log(err))
}
acc.push(element)
return acc
}, [])
}
})
Sample value from array cart
product: {
_id: '5eaf8eeac436dbc9b7d75f35',
name: 'Strawberry',
category: 'organic',
image: '/productImages/australian.jpg',
price: '9.65'
},
quantity: 6
sample cart in db:
_id: 5ec12ea36ccf646ff5aeef0c,
user: 5ec11a8f69ccf46e0e19c5ef,
cart: [
{
date: 2020-05-18T10:26:38.751Z,
_id: 5ec262de5829f081b1ea96d7,
product: 5eaf8eeac436dbc9b7d75f35,
quantity: 8
},
{
date: 2020-05-18T12:11:57.168Z,
_id: 5ec27b8dd2949886308bebd6,
product: 5eaf8f61c436dbc9b7d75f36,
quantity: 6
}
]
I think the best solution is to match the old cart and new cart first in the node.js code then update it, for that below are the steps and code.
Now you have two separate arrays which will be easy to update in 2 queries only, instead of the loop or multiple queries you are using in your code. I also tried to explain it in code comments.
// First get all the new cart productid and quantity in an array
var cartArray = cart.map(obj => {
return {product: obj.product._id, quantity: obj.quantity}
})
Cart.findOne({ user: req.body.params.uid })
.then(userCart => {
var productIds = userCart.cart.map(obj => obj.product)
// array of products id and quantity which are already there in old cart
var productsOld = cartArray.filter(obj => {
return productIds.includes(obj.product)
})
// array of products id and quantity which are not there in old cart
var productsNew = cartArray.filter(obj => {
return !productIds.includes(obj.product)
})
//First, we will add the all new products which are in the new cart
Cart.findOneAndUpdate({ user: req.body.params.uid }, {
$push: {
cart: {
$each: productsNew
}
}
}, {
new: true
}).then(function(updatedUserCart){
// Here we are getting now the updated cart with new products added
// Now we need to update quantity of old products
// Instead of running query in loop, we will update the quantity in array map
// and replace the whole cart in the document
var newCart = updatedUserCart.cart.map(obj => {
var matchProduct = productsOld.filter(oldObj => {
return oldObj.product == obj.product
})
if (matchProduct.length > 0) {
obj.quantity = parseInt(obj.quantity) + parseInt(matchProduct[0].quantity)
return obj
} else {
return obj
}
})
Cart.updateOne({ user: req.body.params.uid }, {
$set: {
cart: newCart
}
})
}).catch(err => console.log(err))
})
Disclaimer: I haven't tried to run the code on my system, so there may be a typo or syntax error, but I hope you understand the flow and logic
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.