map() in node.js, async vs sync? - javascript

I have a segment code like below running in Node.js. And I find it will always goes to else condiction, howerver with masterData is not null.
getOperationDetails(req, res) {
let sql = 'select a.*, b.s*';
sql += ` from ${paymentSheet} a left join ${paymentHisSheet} b on a.id= b.source_id `;
sql += ' where a.id=? ';
func.connPool(sql, id, (err, rows, field) => {
if (err) {
res.json({ code: 400, message: err })
} else {
let masterData = [];
let details = rows.map((row, idx) => {
if (idx === 0) {
masterData.push({
id: row.id,
name: row.name
});
}
return {
operator: row.operator_info,
comments: row.cmt,
status: row.sta
}
})
if (masterData.length > 0 ) {
masterData[0].details = details;
} else {
console.log(sql);
console.log(id);
console.log('=======================');
console.log(masterData);
}
res.json({ code: 200, message: 'ok', data: masterData })
}
})
For example, the console will show like below. Obviously masterData has value. It means 'if' condiction run before map(). Do I have to use async to wait the map() handle the data over?
allConnections:2
select a.*, b.* from payment a left join history b on a.id= b.source_id where a.id=?
83e588cd-9b4b-4592-ac7f-529bfaa9b231
=======================
allConnections:2
allConnections:2
[
{
id: '83e588cd-9b4b-4592-ac7f-529bfaa9b231',
name: 'Jeff'
}
]
My anaysis:
the rows from database should like below
83e588cd-9b4b-4592-ac7f-529bfaa9b231', 'Jeff', 'Operator Peter', 'OK', 0
83e588cd-9b4b-4592-ac7f-529bfaa9b231', 'Jeff', 'Operator Mary', 'NO', 1
83e588cd-9b4b-4592-ac7f-529bfaa9b231', 'Jeff', 'Operator Jet', 'OK', 2
or like below, means no details
83e588cd-9b4b-4592-ac7f-529bfaa9b231', 'Jeff', null, null, null
That is why I use masterData to separate. I think push() should not be taken out the map(), becasue rows maybe return nothing. Will it be like map() is over and push() is still running?
==== P.S. func.connPool====
let mysql = require('mysql');
let db = require('../configs/db');
let pool = mysql.createPool(db);
module.exports = {
connPool (sql, val, cb) {
pool.getConnection((err, conn) => {
if (err) {
console.log('Connection Error:' + err);
cb(err, null, null);
} else {
console.log('allConnections:' + pool._allConnections.length);
let q = conn.query(sql, val, (err, rows,fields) => {
pool.releaseConnection(conn);
if (err) {
console.log('Query:' + sql + ' error:' + err);
}
cb(err, rows, fields);
});
}
});
},

What I suspected is that the push operation is somehow delay because of some code that is not shown here (I am not certain yet).
I ran the following code so many times, I still could not reproduce your problem.
var rows = [
{
id: "123",
name: "test",
},
{
id: "123",
name: "test",
},
{
id: "123",
name: "test",
},
]
let masterData = [];
let details = rows.map((row, idx) => {
if (idx === 0) {
masterData.push({
id: row.id,
name: row.name
});
}
return {
id: row.id,
name: row.name,
}
})
if (masterData.length > 0 ) {
console.log("in");
} else {
console.log(masterData);
console.log('=======================');
}
Could you try whether it goes to else or not for this code.

From this piece of code you are pushing to MasterData only the first row.id and row.name.
( that is specified in the if conditional for just the first index idx === 0 )
So if thats the case you don't need to have this push thing inside the map.
You can take that out of the map and leave the iterator to create only the details array.
You can go with:
let details = rows.map(row => ({
operator: row.operator_info,
comments: row.cmt,
status: row.sta
})
);
let masterData = [{ id: rows[0].id, name: rows[0].name, details }]

Related

Javascript keeps creating duplicate records

I have a csv that I have to read in and have to upload to a MySql database using Prisma. However... Writing all the students to the database works but the entire 'if a group exists, use that group and if it doesn't exist, create it' part doesn't work because he keeps adding duplicate groups into the database, I have tried so many options by now and none seem to work and I'm getting desperate...
router.post('/', async (req, res) => {
fs.createReadStream("./Upload/StudentenEnGroepen001.csv")
.pipe(parse({ delimiter: ",", from_line: 2 }))
.on("data", async (row) => {
let group = null;
let inschrijving = row[6];
if (inschrijving === "Student") {
let parts = row[8].split(",");
let groep = parts[1];
let groepNaam = groep.split(" - ")[0].trim();
const student = await prisma.student.create({
data: {
Code: row[0],
Gebruikersnaam: row[1],
Familienaam: row[2],
Voornaam: row[3],
Sorteernaam: row[4],
Email: row[5],
},
})
const groupCount = await prisma.groep.count({
where: {
Naam: { equals: groepNaam },
}
});
if (groupCount > 0) {
const existingGroup = await prisma.groep.findFirst({
where: {
Naam: { equals: groepNaam },
}
});
group = existingGroup;
} else {
group = await prisma.groep.create({
data: {
Naam: groepNaam,
}
});
}
await prisma.groepstudent.create({
data: {
GroepID: group.ID,
StudentID: student.ID,
},
});
}
})
res.json({message: "Studenten en groepen zijn toegevoegd."});
});
My latest attempt was this but this also doesn't work.
const groupCount = await prisma.groep.count({
where: {
Naam: { equals: groepNaam },
}
});
if (groupCount > 0) {
const existingGroup = await prisma.groep.findFirst({
where: {
Naam: { equals: groepNaam },
}
});
group = existingGroup;
} else {
group = await prisma.groep.create({
data: {
Naam: groepNaam,
}
});
}
I tried to just use 'findFirst' but that also didn't work...
group = await prisma.groep.findFirst({
where: {
Naam: { equals: groepNaam },
}
});
if (group) {
// then use this group
else{
// create group..
...
Would you please include the errors you're getting?
Adding to what Pointy said, try going back to the point where your app was actually working. Then, start adding in small pieces at a time. Run your app each time to see when it bombs out on you. Check your debugger for clues as to when exactly this is happening. These errors should point you in the right direction. Good luck!

Asynchronous Callback to Array.map()

I've just started learning Node.js a few weeks ago.... I am not able to understand why the 'products' array contains null instead of the desired objects....
On Line 13, when I am console logging the object, I get the desired object but I don't understand why they are null when I console log them on Line 40 after the map function has completed it's execution....
If the array length is 2 (which should imply successful pushing) why are the objects stored inside still null instead of the objects that I wanted to store ?
Console Output
Order Schema
exports.getOrders = async (req, res, next) => {
const userOrders = [];
Order.find({ 'user.userId': req.user._id }).then((orders) => {
console.log(orders); // Line 4
async.eachSeries(
orders,
function (order, callback) {
const products = order.products.map((p) => {
const seriesId = p.product.seriesId;
const volumeId = p.product.volumeId;
Series.findById(seriesId).then((series) => {
const volume = series.volumes.id(volumeId);
console.log(volume, p.quantity); // Line 13
return {
seriesTitle: volume.parent().title,
volume: volume,
quantity: p.quantity
};
});
});
console.log('Product Array Length: ', products.length); // Line 21
if (products.length !== 0) {
const data = {
productData: products,
orderData: {
date: order.date,
totalPrice: order.totalPrice
}
};
userOrders.push(data);
callback(null);
} else {
callback('Failed');
}
},
function (err) {
if (err) {
console.log('Could not retrieve orders');
} else {
console.log(userOrders); // Line 40
res.render('shop/orders', {
docTitle: 'My Orders',
path: 'orders',
orders: userOrders,
user: req.user
});
}
}
);
});
};
In line 8, order.products.map returns an array of null. Because this is an asynchronous mapping. For each product, you are calling Series.findById which is a promise and it only returns the value when it resolves. As you are not waiting for the promise to resolve, so it returns null on each iteration.
You have to map all the promises first then call Promise.all to resolve them and after that, you will get the expected value.
exports.getOrders = async (req, res, next) => {
const userOrders = [];
Order.find({ 'user.userId': req.user._id }).then((orders) => {
console.log(orders); // Line 4
async.eachSeries(
orders,
function (order, callback) {
const productPromise = order.products.map((p) => {
const seriesId = p.product.seriesId;
const volumeId = p.product.volumeId;
//ANSWER: Return the following promise
return Series.findById(seriesId).then((series) => {
const volume = series.volumes.id(volumeId);
console.log(volume, p.quantity); // Line 13
return {
seriesTitle: volume.parent().title,
volume: volume,
quantity: p.quantity
};
});
});
// ANSWER: call all the promises
Promise.all(productPromise)
.then(function(products) {
console.log('Product Array Length: ', products.length);
if (products.length !== 0) {
const data = {
productData: products,
orderData: {
date: order.date,
totalPrice: order.totalPrice
}
};
userOrders.push(data);
callback(null);
} else {
callback('Failed');
}
});
},
function (err) {
if (err) {
console.log('Could not retrieve orders');
} else {
console.log(userOrders); // Line 40
res.render('shop/orders', {
docTitle: 'My Orders',
path: 'orders',
orders: userOrders,
user: req.user
});
}
}
);
});
};

Firestore transaction, max documents

It will come at some point that perhaps I will have to update more than 500 documents, but first I have to read and update all the data to be fine. How would you do this with transactions?
I did something similar with _.chunk with batch. But this time I need a transaction but I wouldn't know how to do.
transaction:
if (previousValue.Name !== newValue.Name || previousValue.Image !== newValue.Image) {
const chatRoomQuery = db.collection(chatsCollection).where(userIdsProperty, 'array-contains', userId);
const transactions = _.chunk(chatRoomQuery, maxSize) => {
return db.runTransaction(transaction => {
return transaction.getAll(chatRoomQuery).then(docs => {
docs.forEach(doc => {
let chatRoom = doc.data();
let oldUser = {
Id: previousValue.Id,
Name: previousValue.Name,
Image: previousValue.Image
};
let newUser = {
Id: newValue.Id,
Name: newValue.Name,
Image: newValue.Image
};
let index = chatRoom.Users.indexOf(oldUser);
if (index > -1) {
chatRoom.Users.splice(index, 1, newUser);
transaction.update(doc.ref, chatRoom)
}
})
})
})
});
await Promise.all(transactions);
}
I think I have a syntax error not getting it right.
I leave a screenshot.

Removing an object from an array by a property

I'm writing an endpoint to delete a record from a dummy database. The dummy database right now is written as an array of objects (it will then be changed to a class, then an actual database).
I have a dbHelpers.js file:
module.exports = {
createId(data) {
// ...
},
findById(data, recordId) {
// ...
},
deleteById(data, recordId) {
data.splice(data.findIndex(item => item.id === recordId), 1)
return data;
}
};
And i'm calling it in controllers/envelope.js
exports.deleteEnvelope = async (req, res) => {
try {
const { id } = req.params;
const envelopes = await dbEnvelopes;
const envelope = findById(envelopes, id);
if (!envelope) {
return res.status(404).send({
message: 'Envelope Not Found',
});
}
const updatedEnvelopes = deleteById(envelopes, id);
return res.status(200).send(updatedEnvelopes);
} catch (err) {
res.status(500).send(err)
}
};
However, for some reason, my findIndex function is not working and it's always returning -1. What is wrong with the function?
Below is the dummy db in config/db.js:
const envelopes = [
{
"id": 1,
"title": "Rent",
"budget": 1000
},
{
id: 2,
"title": "Groceries",
"budget": 300
},
{
id: 3,
"title": "Entertainment",
"budget": 400
}
]
module.exports = envelopes;
I think you can use array.filter to remove the object in array by matching the id.
deleteById(data, recordId) {
return data.filter(item => item.id !== recordId)
}

Search for multiple word uisng postgres and javascript

I want to search for multiple words using this query below. when i search for 'document role' I should get all documents that have all document and all document that has role in it using sequelize
function searchDocuments(req, res) {
const limit = req.query.limit || 6,
offset = req.query.offset || 0,
queryString = req.query.q,
splitString = queryString.split(' ');
let querySearch = '';
splitString.forEach((query, index, initial) => {
console.log(initial[index]);
});
if (!queryString) {
return res.status(400).json({
message: 'Invalid search input'
});
}
if (req.decoded.roleId === 1) {
return Document.findAndCountAll({
limit,
offset,
where: {
title: {
$iLike: `%${querySearch}%`
}
},
include: [
{
model: User,
attributes: ['userName', 'roleId']
}
]
})
.then(({ rows: document, count }) => {
if (count === 0) {
return res.status(404).json({
message: 'Search term does not match any document.'
});
}
res.status(200).send({
document,
pagination: pagination(count, limit, offset),
});
})
.catch(error => res.status(400).send(error));
I just want a sequelize query that perform does an OR task with the keyword of title
From the top add the following code:
const limit = req.query.limit || 6,
offset = req.query.offset || 0,
queryString = req.query.q.replace(/ +(?= )/g, ''),
searchQuery = [];
if (!queryString) {
return res.status(400).json({
message: 'Invalid search input'
});
}
if (req.decoded.roleId === 1) {
const splitString = queryString.trim().split(' ');
splitString.forEach((query) => {
const output = { $iLike: `%${query}%` };
searchQuery.push(output);
});
Then add the following where you are querying searchQuery:
where: {
title: {
$or: searchQuery
}
}

Categories

Resources