Update json value in mongodb - node.js

I Need to update the JSON value in MongoDB.
{
INR: 71.7406004869,
BRL: 4.1883509152,
RUB: 63.6918221982,
HRK: 6.7076909206,
TRY: 5.6890271391,
CNY: 7.0266883058,
NOK: 9.1081056713,
NZD: 1.5543233252,
ZAR: 14.6645929132,
USD: 1,
MXN: 19.4436029213,
}
My-schema :
{
id : 1
name: US Dollar
code:USD
rate:1
},
{
id : 2
name: Indian rupees
code:INR
rate: 70.018
}
How to update multiple documents in the collections where I need to check the 'code' field and then update 'rate' field.

Since assuming you are using mongoose as the ODM, to update multiple documents from the object Moldel.bulkWrite() api can be used to have a single round trip to db and update the corresponding documents.
const rateData = {
INR: 71.7406004869,
BRL: 4.1883509152,
RUB: 63.6918221982,
HRK: 6.7076909206,
TRY: 5.6890271391,
CNY: 7.0266883058,
NOK: 9.1081056713,
NZD: 1.5543233252,
ZAR: 14.6645929132,
USD: 1,
MXN: 19.4436029213
};
let bulkOps = [];
Object.keys(rateData).forEach((k, index) => {
bulkOps.push({
updateOne: {
filter: { code: k },
update: { $set: {rate: rateData[k]} }
}
});
});
//Model.bulkWrite returns a promise allows using (then, catch)
Model.bulkWrite(bulkOps)
.then(result => {
console.info("Bulk update information::", result);
})
.catch(e => {
console.error("Error at bulk update::", e);
});

Related

How do I find out the total number of items in a collection? mongoose

I have 100 items in the collection, each item has a "money" field, I need to get the total amount of money from all, preferably without crutches. i don't know how to did it.
const allMoney = async () => {
let count = 0;
await User.find({}).sort({ money: -1 }).forEach(plr => { count+=plr.money });
return count;
}
"user is my model"
Try using the Mongoose aggregation framework with the $group and
$sum operators, just like this:
user.aggregate([
{
$group: {
_id: null,
count: { $sum: "$money" }
}
}
])
The _id: null expression is necessary because a group specification must include it obligatorily. Otherwise Mongoose will throw an error.
You can use aggregate with a group which will easily fetch the total amount for you.
Refer: https://docs.mongodb.com/manual/reference/operator/aggregation/group/
for more clarification.
const allMoney = async () => {
var aggregate = Scheme.aggregate()
aggregate.group({
_id: null,
totalMoney: {$sum: '$money'}
)}
aggregate.exec(function(err, result) {
if (err) return err;
return result;
});
}

Pull only one element from and Array in Mongoose

I was trying to pull only one element from an Array which is a mongo document.
My db looks like this:
product: ['foo','foo','foo'],
...
I want to remove only one element from this array.
My db should Look like this:
product: ['foo','foo'],
...
When I was using model.findByIdAndUpdate( id, { $pull: {product: 'foo'} } )
I loose all my values from product
`
doc.findById(productId)
.then(async (result) => {
if (!result) {
console.log("No Record Found.");
} else {
result.index = undefined;
await result.save();
console.log('Record Updated Successfully.');
}
})
.catrch(err => {
console.log('Error: ', err);
});
`
You can do this to bring the document and then make the required element as undefined and then you can save the modified document back to the database.
Else you can have a better and optimized approach.
`db.doc.update( { _id: 1 }, { $pop: { products: -1 } } )`
Here the first element from the product array will be deleted.
Note: this is the MongoDB shell syntax.

ExpressJS: Sequelize method update need to show updated data as result not num of row updated

I've API using ExpressJS and ORM Sequelize. I'm trying to do update using method update() from Sequelize. By default, it method will return number of row updated. But I want the result is the new data that just updated to show as response.
Here is my code:
update: async function (req, res, next) {
var current_address_id = req.body.current_address_id,
address = req.body.address
PersonalInfo.findOne({
where: {
id: req.params.id
}
}).then(personal => {
Address.create(
{
address: address,
}
).then( resAddress => {
PersonalInfo.update(
{
current_address_id: resAddress.dataValues.id
},
{
where: {
id: req.params.id
}
}
).then(resultUpdate => {
console.log(resultUpdate);
responseUtil.success(res, resultUpdate);
}).catch(err => {
responseUtil.fail(res, err);
})
})
})
}
When I do console.log(resultUpdate); It give me [1] as the num of row updated. What I need is the data of PersonalInfo that just updated.
After consulting the documentation for what returns from the update operation for Sequelize, it returns the following:
an array with one or two elements. The first element is always the
number of affected rows, while the second element is the actual
affected rows (only supported in postgres with options.returning
true.)
So, as you can see from your code, your update is returning an array with the number of affected rows, which is what the documentation says it will do. You can't change what the library itself will return.
You do have access to the values you are updating earlier on in your function, and if you really want, you could do a find on the record you are updating, which will return your model: http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-findOne
You only need to add returning: true at your query. Your code would be like
update: async function (req, res, next) {
var current_address_id = req.body.current_address_id,
address = req.body.address
PersonalInfo.findOne({
where: {
id: req.params.id
}
}).then(personal => {
Address.create(
{
address: address,
}
).then( resAddress => {
PersonalInfo.update(
{
current_address_id: resAddress.dataValues.id
},
{
where: {
id: req.params.id
},
returning: true
}
).then(resultUpdate => {
console.log(resultUpdate);
responseUtil.success(res, resultUpdate);
}).catch(err => {
responseUtil.fail(res, err);
})
})
})
}

MongoDB - find one and add a new property

Background: Im developing an app that shows analytics for inventory management.
It gets an office EXCEL file uploaded, and as the file uploads the app convert it to an array of JSONs. Then, it comapers each json object with the objects in the DB, change its quantity according to the XLS file, and add a timestamp to the stamps array which contain the changes in qunatity.
For example:
{"_id":"5c3f531baf4fe3182cf4f1f2",
"sku":123456,
"product_name":"Example",
"product_cost":10,
"product_price":60,
"product_quantity":100,
"Warehouse":4,
"stamps":[]
}
after the XLS upload, lets say we sold 10 units, it should look like that:
{"_id":"5c3f531baf4fe3182cf4f1f2",
"sku":123456,
"product_name":"Example",
"product_cost":10,
"product_price":60,
"product_quantity":90,
"Warehouse":4,
"stamps":[{"1548147562": -10}]
}
Right now i cant find the right commands for mongoDB to do it, Im developing in Node.js and Angular, Would love to read some ideas.
for (let i = 0; i < products.length; i++) {
ProductsDatabase.findOneAndUpdate(
{"_id": products[i]['id']},
//CHANGE QUANTITY AND ADD A STAMP
...
}
You would need two operations here. The first will be to get an array of documents from the db that match the ones in the JSON array. From the list you compare the 'product_quantity' keys and if there is a change, create a new array of objects with the product id and change in quantity.
The second operation will be an update which uses this new array with the change in quantity for each matching product.
Armed with this new array of updated product properties, it would be ideal to use a bulk update for this as looping through the list and sending
each update request to the server can be computationally costly.
Consider using the bulkWrite method which is on the model. This accepts an array of write operations and executes each of them of which a typical update operation
for your use case would have the following structure
{ updateOne :
{
"filter" : <document>,
"update" : <document>,
"upsert" : <boolean>,
"collation": <document>,
"arrayFilters": [ <filterdocument1>, ... ]
}
}
So your operations would follow this pattern:
(async () => {
let bulkOperations = []
const ids = products.map(({ id }) => id)
const matchedProducts = await ProductDatabase.find({
'_id': { '$in': ids }
}).lean().exec()
for(let product in products) {
const [matchedProduct, ...rest] = matchedProducts.filter(p => p._id === product.id)
const { _id, product_quantity } = matchedProduct
const changeInQuantity = product.product_quantity - product_quantity
if (changeInQuantity !== 0) {
const stamps = { [(new Date()).getTime()] : changeInQuantity }
bulkOperations.push({
'updateOne': {
'filter': { _id },
'update': {
'$inc': { 'product_quantity': changeInQuantity },
'$push': { stamps }
}
}
})
}
}
const bulkResult = await ProductDatabase.bulkWrite(bulkOperations)
console.log(bulkResult)
})()
You can use mongoose's findOneAndUpdate to update the existing value of a document.
"use strict";
const ids = products.map(x => x._id);
let operations = products.map(xlProductData => {
return ProductsDatabase.find({
_id: {
$in: ids
}
}).then(products => {
return products.map(productData => {
return ProductsDatabase.findOneAndUpdate({
_id: xlProductData.id // or product._id
}, {
sku: xlProductData.sku,
product_name: xlProductData.product_name,
product_cost: xlProductData.product_cost,
product_price: xlProductData.product_price,
Warehouse: xlProductData.Warehouse,
product_quantity: productData.product_quantity - xlProductData.product_quantity,
$push: {
stamps: {
[new Date().getTime()]: -1 * xlProductData.product_quantity
}
},
updated_at: new Date()
}, {
upsert: false,
returnNewDocument: true
});
});
});
});
Promise.all(operations).then(() => {
console.log('All good');
}).catch(err => {
console.log('err ', err);
});

Make api call if value from mongoDB is null

I am developing an app and I am using MEAN stack. I have values saved in a database using MongoDB. I want to use those values to make API calls but only if a value is null. Now it is successfully getting those values from the database and making the calls to the API but I don't know how to check if the value is null, I have tried basically everything but I think I don't understand completely NodeJS and that it is asynchronous. This is the code that works but doesn't check if the value is null:
var makeApiCalls = function (workerId) {
var Model = mongoose.model('Tweet'.concat(workerId), Tweet.tweetSchema);
return Model.find({},{ _id: 1, message: 1}).then(messages =>
Promise.all(
messages.map(({ _id, message }) =>
api.sentiment(message).then(result =>
Model.findOneAndUpdate({ _id }, { resultOfTheCall: result }, { new: true })
.then( updated => { console.log(updated); return updated })
)
)
)
)
};
The mongoose model has a field called resultOfTheCall and I need to check if that value is null and only in that case, I want to make a call to the API with the field message.
This is the console.log of one of the message:
{
_id: 5b85c83b413a2b1473e7122a,
date: 'Tue Aug 28 22:10:02 +0000 2018',
message: 'la gente quiere y no viene',
resultOfTheCall: 0.5931016939587707,
__v: 0 }
Simply filter the messages before making the Promise.all.
var makeApiCalls = function(workerId) {
var Model = mongoose.model('Tweet'.concat(workerId), Tweet.tweetSchema);
return Model.find({}, {
_id: 1,
message: 1,
resultOfTheCall: 1
}).then(messages => {
// filter the mssages here those for which to make the call and the others
var toCallArray = messages.filter(x => x.resultOfTheCall == null)
var noCallArray = messages.filter(x => x.resultOfTheCall != null)
// now do the calls for only those which do not have resultOfTheCall
return Promise.all(
toCallArray.map(({_id, message}) =>
api.sentiment(message).then(result =>
Model.findOneAndUpdate({
_id
}, {
resultOfTheCall: result
}, {
new: true
})
.then(updated => {
console.log(updated);
return [...noCallArray, ...toCallArray]
})
)
)
)
})
};

Resources