I'm doing some testing for performance and was looking at Promise.all() in node/js. However, after testing this it's actually slower than using await for the 3 promises I want to resolve. I'm simply returning some data back from a mongodb database.
Am I doing something wrong here or is this just due to the way the event loop is working?
Promise.all() : 234.820ms
// Init db connection
const db = client.db('docker-client1');
const productsCollection = db.collection('ICProductData');
const rulesCollection = db.collection('SPRuleData');
const customersCollection = db.collection('ARCustomerData');
// Main function
const CustomerCode = 'FINE';
const ProductCode = 'BEDCABINET';
let customers = customersCollection
.find({ _id: CustomerCode })
.project({ PriceCode: 1, BillToAccountCode: 1 })
.toArray();
let products = productsCollection
.find({ _id: ProductCode })
.project({ 'Price.PriceCode': 1, 'Price.SellingPrice': 1 })
.toArray();
let rules = rulesCollection
.find({
$and: [
{
$or: [
{
$and: [
{ What1Code: ProductCode, What1Type: 'Product' },
{ Who1Code: CustomerCode, Who1Type: 'Customer' }
]
}
]
}
]
})
.toArray();
const results = await Promise.all([customers, products, rules]);
console.timeEnd();
Simply using await : 127.239ms
// Init db connection
const db = client.db('docker-client1');
const productsCollection = db.collection('ICProductData');
const rulesCollection = db.collection('SPRuleData');
const customersCollection = db.collection('ARCustomerData');
// Main function
const CustomerCode = 'FINE';
const ProductCode = 'BEDCABINET';
const custReq = await customersCollection
.find({ _id: CustomerCode })
.project({ PriceCode: 1, BillToAccountCode: 1 })
.toArray();
const prodReq = await productsCollection
.find({ _id: ProductCode })
.project({ 'Price.PriceCode': 1, 'Price.SellingPrice': 1 })
.toArray();
let rulesReq = await rulesCollection
.find({
$and: [
{
$or: [
{
$and: [
{ What1Code: ProductCode, What1Type: 'Product' },
{ Who1Code: CustomerCode, Who1Type: 'Customer' }
]
}
]
}
]
})
.toArray();
console.timeEnd();
The method toArray() does not return a Promise in Old versions of Mongo. This could be the explanation about timings. You could put a console.log with timing after each toArray() they should run in the same millisecond (same tick). If this is not the case, it could be an indication that toArray() is waiting for the response... so you are running sequentially. You could try to resolve this with: let myProm = collection.find(filter).exec()
Related
I am trying to remove an object from array in in firestore, but encountered an obstacle what are the requirement or the reference to do the removal ? does one key value in the object sufficient to do the remove or should the object by identical to the one that is getting removed ?
const deleteWeek = async () => {
const docRef = doc(db, 'Weeks', id);
await updateDoc(docRef, {
weeks: arrayRemove({
weekId: '7518005f-7b10-44b6-8e0a-5e41081ee064',
}),
});
};
deleteWeek();
}
however week in data base looks like this
{name ,"Week 2"
days : [/*data all kinds*/]
weekId : "7518005f-7b10-44b6-8e0a-5e41081ee064"}
If it's an array of object, then you need to know the whole object to use arrayRemove() For example, if the a document looks like this:
{
...data
weeks: [
{
name: "Week 2",
days: [/*data all kinds*/]
weekId: "7518005f-7b10-44b6-8e0a-5e41081ee064"}
}
]
}
You'll have to pass the entire week object in arrayRemove(). It might be better to store such data in sub-collections instead so you can query/delete a specific one.
Since there is no function in firestore to delete only a element in array, you need to make arrayRemove refer to the same object you want to delete, then create a new object and insert it with arrayUnion method
in my case, i use to below
const { leave,date,email } = req.body;
const attendanceRef = admin.firestore().collection('Attendance').doc(`${email}`);
const attendanceData = await attendanceRef.get();
const attendanceRecord = attendanceData.data().attendance;
const removeTarget = attendanceRecord.find((item) => item.date === date);
await attendanceRef.update({
attendance: admin.firestore.FieldValue.arrayRemove(removeTarget),
})
const obj = {
...removeTarget,
"leave": leave,
}
await attendanceRef.set({
attendance: admin.firestore.FieldValue.arrayUnion(obj),
},{ merge: true })
const newAttendance = await attendanceRef.get();
const newAttendanceRecord = newAttendance.data().attendance;
return await res.json({
message: '퇴근시간이 저장되었습니다.',
attendance:newAttendanceRecord
});
after update, it maybe if error occured.
if error occured, you need all working cancel.
this case, you may want to use batch method
const admin = require('firebase-admin');
module.exports = async function(req,res) {
const { leave,date,email } = req.body;
const batch = admin.firestore().batch();
const attendanceRef = admin.firestore().collection('Attendance').doc(`${email}`);
const attendanceData = await attendanceRef.get();
const attendanceRecord = attendanceData.data().attendance;
const removeTarget = attendanceRecord.find((item) => item.date === date);
// await attendanceRef.update({
// attendance: admin.firestore.FieldValue.arrayRemove(removeTarget),
// })
batch.update(
attendanceRef,{ attendance: admin.firestore.FieldValue.arrayRemove(removeTarget) }
)
const obj = {
...removeTarget,
"leave": leave,
}
// await attendanceRef.set({
// attendance: admin.firestore.FieldValue.arrayUnion(obj),
// },{ merge: true })
batch.set(
attendanceRef, { attendance: admin.firestore.FieldValue.arrayUnion(obj) },{ merge: true }
)
await batch.commit();
const newAttendance = await attendanceRef.get();
const newAttendanceRecord = newAttendance.data().attendance;
return await res.json({message: '퇴근시간이 저장되었습니다.',attendance:newAttendanceRecord});
}
hope help this for you
I have two models in my aplication, Delivery and DeliveryProblem.
DeliveryProblem has a PK (delivery_id) from Delivery:
static associate(models) {
this.belongsTo(models.Delivery, {
foreignKey: 'delivery_id',
as: 'delivery',
});
}
I need select all Deliveries that have a Delivery Problem.
In my Controller, a have the follow method:
async index(req, res) {
const response = await DeliveryProblem.findAll({
order: ['id'],
attributes: ['delivery_id'],
});
// Filter all Deliveries with problem
const ids = [...new Set(response.map((x) => x.delivery_id))];
const deliveries = Delivery.findAll({
where: , // <<< How can I filter ?
order: ['id'],
});
return res.json(deliveries);
}
const Sequelize = require('sequelize')
const Op = Sequelize.Op
...
// Filter all Deliveries with problem
const ids = [...new Set(response.map((x) => x.delivery_id))];
const deliveries = Delivery.findAll({
where: {
id: {
[Op.in]: ids
}
},
order: ['id'],
});
like js code
when I do this
it will query up to 1000 times,
can it query once?
const promises = idList.map(async id => {
const query = new Parse.Query("results");
query.equalTo("id", id);
query.descending("createdAt");
query.first()
});
const prPool = await Promise.all(promises);
You need to use aggregate. It would be something like this:
const pipeline = [
{ match: { id: id } },
{ sort: { createdAt: -1 } },
{ group: { objectId: '$id', lastCreatedAt: { $first: '$createdAt' } } }
];
const query = new Parse.Query('results');
const prPool = await query.aggregate(pipeline);
I am new to nodejs and promise based request. I want to fetch the data from a remote server in a loop, and then create a JSON object from all fetched data.
const fetch = require('node-fetch');
const users = [];
const ids = await fetch('https://remote-server.com/ids.json');
console.log(ids);
// [1,2,3]
ids.forEach(id => {
var user = await fetch(`https://remote-server.com/user/${id}.json`);
users.push(user);
});
console.log(users);
expected output
[
{
name: 'user 1',
city: 'abc'
},
{
name: 'user 2',
city: 'pqr'
},
{
name: 'user 3',
city: 'xyz'
}
]
So to launch in parallel:
const ids = await fetch('https://remote-server.com/ids.json');
const userPromises = ids.map(id => fetch(`https://remote-server.com/user/${id}.json`));
const users = await Promise.all(userPromises);
to launch in sequence:
const users = [];
const ids = await fetch('https://remote-server.com/ids.json');
for(const id of ids){
const user = await fetch(`https://remote-server.com/user/${id}.json`);
users.push(user);
}
You forgot to add async in the forEach:
ids.forEach(async (id) => { // your promise is in another function now, so you must specify async to use await
var user = await fetch(`https://remote-server.com/user/${id}.json`);
users.push(user);
});
I'm building an app in Express and using Postgres for my database, Sequelize for ORM.
In my database each Post can have one of the 5 types, 1, 2, 3, 4, 5.
I want to show the amount of all the posts by type.
router.route('/post).get(async (req, res) => {
const postOne = await Post.findAll({
where: {
state: 1
}
});
const postTwo = await Post.findAll({
where: {
state: 2
}
});
res.send({ postOne: postOne.length, postTwo: postTwo.length });
I can write like this for all of the 5 types, but I was wondering if there was any shorter way to do it so that I don't have to write the same code 5 times.
Thanks!
const getPostWithType = (type) => Post.findAll({
where: {
state: type
}
});
Now you can await getPostWithType(1) instead. Or even better:
const postTypes = [1,2,3,4,5];
const allPosts = await Promise.all(postTypes.map(getPostWithType));
// allPosts is now an array with the results. You can map it again to get the lengths
const allPostLengths = allPosts.map(p => p.length);
what about using an array? Like below...
let promiseArray = [];
for (let i = 1; i <= 5; i++) {
let promise = Post.findAll({
where: {
state: i
}
});
promiseArray.push(promise);
}
Promise.all(promiseArray).then(function(response) {
//Do whatever...
});