mongoose find one and update function - node.js

Suppose that we have a shopping cart in the site, we have specified number of a good in database. Whenever the user wants to validate his/her cart and finalize it, I want to subtract the number of goods that the user purchased from total count of the product. How can I do that?
router.post('/done', (req, res) => {
// substract from the count
for (var i = 0; i < req.body.cart.length; i++){
Product.findOne({_id: req.body.cart[i]._id}).exec((err, result) => {
result.count = result.count - req.body.cart[i].count;
// update the value of result.count and save it on database
})
}
})

You just need to save, and also check for errors.
router.post('/done', (req, res) => {
// substract from the count
for (var i = 0; i < req.body.cart.length; i++){
Product.findOne({_id: req.body.cart[i]._id}).exec((err, result) => {
if(result)
{
result.count = result.count - req.body.cart[i].count;
result.save((err) => {
if (err) // do something
});
}
//If you don't find the product for some reason, do something
})
}
})

You can use mongoose's findOneAndUpdate() and $inc reference operator with a negative value to decrement the count.
Docs
The following update() operation uses the $inc operator to decrease the quantity field by 2 (i.e. increase by -2) and increase the "metrics.orders" field by 1:
db.products.update(
{ sku: "abc123" },
{ $inc: { quantity: -2, "metrics.orders": 1 } }
)
Making those changes
'use strict';
router.post('/done', (req, res) => {
let {cart} = req.body;
if (!Array.isArray(cart) || cart.length === 0) {
return res.status(400).send({
msg: 'Empty cart'
});
}
let updates = cart.map(item => {
return Product.findOneAndUpdate({
_id: item._id
}, {
$inc: {
count: -1 * item.count
}
}, {
upsert: false
});
});
Promise.all(updates).then(() => {
return res.status(200).send({
msg: 'inventory updated'
});
}).catch(err => {
console.log('err', err.stack);
return res.status(500).send({
msg: 'inventory update failed!'
});
});
});

Related

Iterating over an Array and update db asynchronously

I am using Express node, MongoDB In this App.
Idea: send Post request contains an array of objects, => check if any object is existed before, => add the
not existed elements to the array in the document in one shot.
problem: Each time I sent a post request only one element is added. I have to repeat 3 times in order to add an array of 3 elements.
solution tried: before I used promise.all() nothing has been added. after I used promise.all only one element is added
code:
.post(cors.corsWithOptions, authenticate.verifyUser, (req, res, next) => {
let favstoAdd = req.body.favorites;
let user = req.user;
//check if the user have a favorites already and create favorites if it is not existed
var p1 = Favorites.findOne({ user: user._id })
.then((res_user) => {
if (res_user !== null) {
}
else {
Favorites.create({ user: user._id, favorites: [] });
}
});
//check if the dish Existed before in the favs and add them to the new filtered array
var altered_favstoAdd = [];
var p2 = favstoAdd.map((fav) => {
Favorites.findOne({ favorites: fav._id })
.then((dish) => {
if (dish == null) {
altered_favstoAdd.push(fav);
}
})
.catch((err) => { next(err) });
});
var p3 = promise.all([p1, p2]).then(values => {
//update favorite
for (let i = 0; i < altered_favstoAdd.length; i++) {
let alt_fav = altered_favstoAdd[i];
Favorites.update({ user: user._id }, { $push: { favorites: alt_fav } }, { new: true }, (err, resp) => {
if (err) { next(err); }
})
}
});
//respond with the favorite item
promise.all([p3]).then(
Favorites.findOne({ user: user._id })
.then((favorite) => { res.json(favorite); })
.catch((err) => { next(err) })
)
})
I think the problem is in the map function :
var p2 = favstoAdd.map((fav) => {
Favorites.findOne({ favorites: fav._id })
.then((dish) => {
if (dish == null) {
altered_favstoAdd.push(fav);
}
})
.catch((err) => { next(err) });
});
this function does not itereate over the whole array some thing is preventing it.
any Ideas??

Return in json more than one result from query

can someone tell me how Can I response from this query, count() and list of products in one result??
Because at this moment its only return me Array with limit, i want count() without limit, of all products:
Array [ Object, Object, Object, Object, Object ]
router.get('/products', function (req, res) {
var size = parseInt(req.query.pageSize);
if (req.query.pageNumber == 1) {
var page = 0;
} else {
var page = parseInt(req.query.pageNumber) * req.query.pageSize - req.query.pageSize;
}
Product.count()
.exec(function (err, products) {
if (err) {
res.status(404).json({
message: 'Can not download this list'
})
} else {
Product.find().skip(page).limit(size)
.exec(function (err, products) {
if (err) {
res.status(404).json({
message: 'Can not download this list'
})
} else {
res.json(products);
}
})
}
})
});
you can do it in this way :
res.json({ "key1": value1, "key2": value2})

How to delete Element In MongoDB property's array with MongooseJS?

I cannot remove an element inside of an array that is a property of a MongoDB Model.
Please remember this is a NodeJS module mongooseJS and not the real MongoDB so functionalities are not the same..
GOAL: Delete an object from the statusLiked array. | I have also confirmed that the value of status.id is correct.
Model:
Const userSchema = new mongoose.Schema({
myStatus: Array,
statusLiked: Array,
)};
Delete:
1. Deletes the status(works). 2. Delete the status from User.statusLiked(no work).
exports.deleteStatus = (req, res, next) => {
var CurrentPost = req.body.statusid; // sends in the status.id
Status.remove({ _id: CurrentPost }, (err) => {
if (err) { return next(err); }
// vvvv this vvv
User.update( {id: req.user.id}, { $pullAll: {_id: CurrentPost }, function(err) { console.log('error: '+err) } });
req.flash('success', { msg: 'Status deleted.' });
res.redirect('/');
});
};
What happens: The specific status(object) is deleted from the database. But the status still remains in the User.statusLiked array.
What I want to happen: Status to be deleted from the User.statusLiked array and the status to be deleted from the database. Then, reload the page and display a notification.
I got it to work somehow. Working code:
exports.deleteStatus = (req, res, next) => {
var CurrUser = req.body.userid;
var CurrentPost = req.body.post;
Status.remove({ _id: CurrentPost }, (err) => {
if (err) { return next(err); }
console.log('meeee'+CurrentPost+'user: ' +CurrUser);
req.flash('success', { msg: 'Status deleted.' });
res.redirect('/');
});
User.update(
{ _id: new ObjectId(CurrUser)},
{ $pull: { myStatus : { _id : new ObjectId(CurrentPost) } } },
{ safe: true },
function (err, obj) {
console.log(err || obj);
});
};

MongoDB Bulk Insert Ignore Duplicate

I've Googled around and can't find any solid information on how to ignore duplicate errors when using bulk insert.
Here's the code I'm currently using:
MongoClient.connect(mongoURL, function(err, db) {
if(err) console.err(err)
let col = db.collection('user_ids')
let batch = col.initializeUnorderedBulkOp()
ids.forEach(function(id) {
batch.insert({ userid: id, used: false, group: argv.groupID })
})
batch.execute(function(err, result) {
if(err) {
console.error(new Error(err))
db.close()
}
// Do some work
db.close()
})
})
Is it possible? I've tried adding {continueOnError: true, safe: true} to bulk.insert(...) but that didn't work.
Any ideas?
An alternative is to use bulk.find().upsert().replaceOne() instead:
MongoClient.connect(mongoURL, function(err, db) {
if(err) console.err(err)
let col = db.collection('user_ids')
let batch = col.initializeUnorderedBulkOp()
ids.forEach(function(id) {
batch.find({ userid: id }).upsert().replaceOne({
userid: id,
used: false,
group: argv.groupID
});
});
batch.execute(function(err, result) {
if(err) {
console.error(new Error(err))
db.close()
}
// Do some work
db.close()
});
});
With the above, if a document matches the query { userid: id } it will be replaced with the new document, otherwise it will be created hence there are No duplicate key errors thrown.
For MongoDB server versions 3.2+, use bulkWrite as:
MongoClient.connect(mongoURL, function(err, db) {
if(err) console.err(err)
let col = db.collection('user_ids')
let ops = []
let counter = 0
ids.forEach(function(id) {
ops.push({
"replaceOne": {
"filter": { "userid": id },
"replacement": {
userid: id,
used: false,
group: argv.groupID
},
"upsert": true
}
})
counter++
if (counter % 500 === 0) {
col.bulkWrite(ops, function(err, r) {
// do something with result
db.close()
})
ops = []
}
})
if (counter % 500 !== 0) {
col.bulkWrite(ops, function(err, r) {
// do something with result
db.close()
}
}
})

Sequlize callback when using transaction

In my application, I have an Model say it is Record, and a Record may have several Attachment which can be uploaded to the server.
Generally, when creating a Record with Attachment(files), I will upload and save the files first, then save the record, like this:
function createOrUpdateInfo(req, res, next) {
var record = req.body;
var attachmentIds = (record.files || []).map(function (a) {
return a.id;
});
var attachmentFilter = {
where: {
id: {
$in: attachmentIds || []
}
}
};
DB.sequelize.transaction(function (t) {
var pro;
if (record.id) {
//update
//update the basic information first
return Record.update(record, {
where: {
id: req.params.id
}, transaction: t
}).then(function (num, infos) {
//find the record just saved.
return Record.findById(req.params.id).then(function (record) {
//find the attachmens which have been saved
return Attachment.findAll(attachmentFilter).then(function (atts) {
//update the record, create the association.
return record.setFiles(atts, {transaction: t});
});
})
});
} else {
//save
return Record.create(record, {transaction: t}).then(function (record) {
return Attachment.findAll(attachmentFilter).then(function (atts) {
return record.setFiles(atts, {transaction: t});
});
});
}
}).then(function (result) {
Util.sendJson(res, result)
}).catch(function (err) {
next({message: err.message, code: 500});
});
}
As shown, there are too many nested callbacks when create or update a Record.
Is this can be fixed?
I've reorganized your code a bit. Hope it helps.
function createOrUpdateInfo(req, res, next) {
var record = req.body;
var attachmentIds = (record.files || []).map(function (a) {
return a.id;
});
var attachmentFilter = {
where: {
id: {
$in: attachmentIds || []
}
}
};
DB.sequelize.transaction(function (t) {
var pro;
return (function () {
if (record.id) {
//update
//update the basic information first
return Record.update(record, {
where: {
id: req.params.id
}, transaction: t
}).then(function (num, infos) {
//find the record just saved.
return Record.findById(req.params.id);
});
} else {
//save
return Record.create(record, {transaction: t});
}
}()).then(function () {
//find the attachmens which have been saved
return Attachment.findAll(attachmentFilter);
}).then(function (atts) {
//update the record, create the association.
return record.setFiles(atts, {transaction: t});
});
}).then(function (result) {
Util.sendJson(res, result)
}).catch(function (err) {
next({message: err.message, code: 500});
});
}

Resources