sqlite3 (node js) - how to see if you are on last row in db.each - node.js

I am trying to see if i am on the last row when using db.each
accountDb.each("SELECT * FROM account", (err, row) => {
// how do i see if row is last?
}
I am not sure if there is a function to check, or a variable or something.

You can use all to return all rows and then use a for loop:
accountDb.all("SELECT * FROM account", (err, rows) => {
if (err) throw err;
const numRows = rows.length;
for (let i = 0; i < numRows; i++) {
if (i === numRows - 1) {
// Last row...
}
}
}

check row is null or empty?Sorry, I don't know much about nodejs api ^_^

Related

Can't set headers after they are sent to the client [ERR_HTTP_HEADERS_SENT]

I understood why it was an error, I tried the suggestions like return or do function aysnc, but I could not solve it.
I have documents as long as find.lenght and 100 sub-documents. That's why I am use two loop. When first iteration is complete and second matching value is found, server is crashed. Without server it works.
I have documents called 0,1,2 and there are 100 crypto coins records from 0 to 100 in them. I added an image. For example, USDT is at [0,3], [1,43], [2,13] and I want to send all of three.
app.post('/', (req, res) => {
print(req, res)
})
function print(req, res) {
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("cryptoDb");
dbo.collection("coinTable").find({}).toArray(function (err, find) {
if (err) throw err;
for (i = 0; i < find.length; i++) {
let found = false;
for (j = 0; j < 100; j++) {
//console.log(i + " " + j)
let id = Capitalize(req.body.coinName);
if (find[i].result[j].name == id || find[i].result[j].symbol == id.toUpperCase()) {
// console.log(find[i].result[j]);
res.send(find[i].result[j]);
found = true;
}
}
if (!found) {
console.log("Not found")
}
}
db.close();
});
});
function Capitalize(s) {
return s[0].toUpperCase() + s.slice(1).toLowerCase();
}
}
Thank you so much !
This error comes from attempting to send more than one response to the same http request.
You have res.send(find[i].result[j]); inside a for loop and you do not stop the inner loop after sending a response.
Thus, this code is capable of attempting to send multiple responses to the same request which you cannot do.
It's unclear from the code exactly what the desired solution is. If you only want to send the first response, then you can close the db and return after you send a response which will terminate both for loops.
If you intend to send multiple pieces of data, then accumulate the data you want to send in an array and send all the data once after all the loops are done.
If you're trying to send an array of all matching results, you can do this:
app.post('/', (req, res) => {
print(req, res)
})
function print(req, res) {
MongoClient.connect(url, function(err, db) {
if (err) {
console.log(err);
res.sendStatus(500);
return;
}
var dbo = db.db("cryptoDb");
dbo.collection("coinTable").find({}).toArray(function(err, find) {
if (err) {
console.log(err);
res.sendStatus(500);
db.close();
return;
}
const id = Capitalize(req.body.coinName);
const idUpper = id.toUpperCase();
const results = [];
for (let findItem of find) {
for (let j = 0; j < 100; j++) {
if (findItem.result[j].name == id || findItem.result[j].symbol == idUpper) {
results.push(findItem.result[j]);
}
}
}
res.send(results);
if (!results.length) {
console.log("No results");
}
db.close();
});
});
function Capitalize(s) {
return s[0].toUpperCase() + s.slice(1).toLowerCase();
}
}
Other Notes:
I changed the if (err) { ... } handling on your database call to actually send an error response. All paths through your request handler need to send a response or cause a response to be sent.
The hard coded loop from 0 to 99 is a bit odd as you don't check if the .result array actually has that many entries in it. That could result in a run-time error if the data isn't exactly how you are expecting it.
You don't have any validation of the req.body data you are expecting. All data arriving from the user should be validated before assuming it is what you are expecting.
You have res.send inside of your for loop, im assuming you want it to quit once its done, so add break to your loop.
var senddata = [];
for (j = 0; j < 100; j++) { // <-- For loop, it will send multiple times
// console.log(i + " " + j)
let id = Capitalize(req.body.coinName);
if (find[i].result[j].name == id || find[i].result[j].symbol == id.toUpperCase()) {
// console.log(find[i].result[j]);
senddata[senddata.length] = find[i].result[j]); // Add to array
found = true;
}
if (!found) {
console.log("Not found")
}
}
res.send(JSON.stringify({senddata})); // Send unparsed data

How to add row in google sheet synchronously?

I'm using google-spreadsheet library to access and insert data to Google Sheets. I was able to add multiple rows but each row is being added in no particular order, I guess due to the addRow() async behavior.
Example data is:
let myData = [{id: "1", fname: "John"}, {id: "2", fname: "Matt"}, {id: "3", fname: "Paul"}]
for (let i = 0; i < myData.length; i++) {
let row = myData[i];
// Async call to insert row.
doc.addRow(sheetIndex, row, (err) => {
if (err) throw err;
});
}
For-loop iterates and passes each row object to addRow() but it doesn't care what the order is when each row gets inserted to Googlesheets.
I've tried doing an async-await approach to wait for doc.addRow() before it iterates to next row object but I have no luck. Is there a way to achieve the insertion in the same order I pass it? Thanks in advance! :)
You couldn't await the function probably because it does't return Promise. So, lets promisify that function first.
function asyncAddRow(sheetIndex, row) {
return new Promise((res, rej) => {
doc.addRow(sheetIndex, row, (err) => {
if (err) rej(err);
else res(true);
});
})
}
Now, instead of calling doc.addRow you call our asyncAddRow. Since it returns a promise so you can await it now. Like this:
for (let i = 0; i < myData.length; i++) {
let row = myData[i];
await asyncAddRow(sheetIndex, row);
}
You should use the method append()
let values = [
[
// Cell values ...
],
// Additional rows ...
];
let resource = {
values,
};
this.sheetsService.spreadsheets.values.append({
spreadsheetId,
range,
valueInputOption,
resource,
}, (err, result) => {
if (err) {
// Handle error.
console.log(err);
} else {
console.log(`${result.updates.updatedCells} cells appended.`);
}
});
More info there

Unable to equate id's of two object in nodejs to the objects returned from mongodb

Here is the code snipped which runs when I open a webpage from browser, it queries all the users, and just removes the users object who is querying it.
I am trying to do it by equating their _id's field which is generated by default in mongodb and is always unique, I am able to print each object's _id field but when i try it in if condition it fails to enter the if condition,
user.find({}, { 'local.name': 1, route_id: 1, stop_number: 1, _id: 1 }, function (err, allusers) {
if (err) throw err;
var len = allusers.length;
for (var index = 0; index < len; index++) {
console.log(allusers[index]._id);
console.log(index);
if (allusers[index]._id === req.user._id) {
console.log("here");
allusers.splice(index, 1);
}
}
res.send(allusers);
})
Here is the output of above:
GET /javascripts/delete_user.js 304 1ms
588f2aded1902a1b08959145
0
58bd116c84fdb70a9c4f34aa
1
can't figure where I am going wrong, and yes, req.user._id equals to the first user's id i.e. 588f2aded1902a1b08959145, still does not enters if condition, if someone can please point me in the right direction.
Try
if( allusers[index]._id.toString() === req.user._id.toString() ) {
console.log("here");
allusers.splice(index,1);
}
Works for me :)
I found the solution to the error, I was removing the object as soon as I found it, which was reducing the length of allusers array and when it will try to reach last index which is now undefined as I spliced it already it was reading the -id property of undefined.
Here is the correct code:
user.find({}, { 'local.name': 1, route_id: 1, stop_number: 1, _id: 1 }, function (err, allusers) {
if (err) throw err;
var len = allusers.length;
var to_remove;
for (var index = 0; index < len; index++) {
if (allusers[index]._id === req.user._id) {
to_remove = index;
}
}
allusers.splice(to_remove, 1);
res.send(allusers);
})

Any better solution about asynchronous query form main table and sub table?

I have two tables, tb_article and tb_attach_url, like this
==============tb_article=================
id title content
1 "echo" "test"
2 "foo" "bar"
==============tb_attach_url==============
id article_id url_val
1 2 "http://.../foo.png"
2 2 "http://.../bar.png"
3 1 "http://.../test.png"
My scenario is like this,
I want show a list of tb_article,
but tb_attach_url's information need also.
My solution is like this:
function load_article_urls(id, idx, callback){
connection.query("select url_str from tb_attach_url where article_id = ?", [id], function(err, results){
if (err) throw err;
var images = [];
for (var j = 0; j < results.length; j++){
images.push(results[j]["url_str"]);
}
callback(idx, images)
});
}
function load_article(req, res){
connection.query('select * from tb_article where id = ?', [req.query.id], function(err, results){
if (err) throw err;
var cnt = 0;
for (var i = 0; i < results.length; i++){
load_article_urls(results[i].id, i, function(idx, urls){
results[idx]["urlset"] = urls;
cnt++;
if (cnt == results.length){
//waiting for all back
res.render('list_article', { article_list: results});
}
});
}
});
}
I think this implement is little ugly, and want to know some better ways.
Thanks for any help.
You can use async.map (GitHub) to do something like this:
async.map(results,
function (err, callback) { /* Call callback with the urls as a parameter here */ },
function (err, allUrls) {
// Combine results and allUrls - they are in the same order.
})
Or use some of the other functionalities of async to achieve a similar effect.

node.js : For each over rows and update asynchronously?

I need to query rows from a database, process some information per row, and then update each row with the result.
This is my example code where the intention is to loop over each row and update the label:
var mysql = require('mysql');
var db = mysql.createConnection(config.database);
db.connect(function() {
db.query('SELECT id FROM testTable', function (err, rows) {
if (err) {
console.log(err);
} else {
if (rows.length) {
for (var i = 0, len = rows.length; i < len; i++) {
var row = rows[i];
console.log(row);
var label = "Label_"+row.id;
db.query('UPDATE testTable SET label = ? WHERE id = ?', [label, row.id], function(err, result) {
if (err) {
console.log(err);
} else {
console.log("Set label on row %s", row.id);
}
})
}
}
}
})
});
The output of this is:
{ id: 1 }
{ id: 2 }
{ id: 3 }
{ id: 4 }
Set label on row 4
Set label on row 4
Set label on row 4
Set label on row 4
So, as you can see, I've updated row 4 four times instead of four rows once each. Whilst I new the queries would be non-blocking, I thought the values would change for each one.
I know I can change my code to use rows.forEach(function(){...}) and that then executes each UPDATE one after the other and that would be ok. But to help my understanding I would like to know how I can correctly execute the updates asynchronously.
Your row variable is a closure in the callback function. The callback function doesn't get called until you've looped through all your results list. The sql queries are correct, but printing out the value of row.id in each callback just gives you the last iteration of the for loop each time because that is the state of the closure for every callback.
You can avoid this by using the underscore module. It can also help in making you logic simpler.
npm install underscore
Then your code would look like this:
var mysql = require('mysql');
var _ = require('underscore');
var db = mysql.createConnection(config.database);
db.connect(function() {
db.query('SELECT id FROM testTable', function (err, rows) {
if (err) { console.log(err); return; }
_.each(rows, function(one) {
console.log(one);
var label = "Label_"+one.id;
var sql = 'UPDATE testTable SET label = ? WHERE id = ?';
db.query(sql, [label, one.id], function(err, result) {
if(err) { console.log(err); return; }
console.log("Set label on row %s", one.id);
});
});
});
});

Resources