inserting multiple dependent tables at once in sqlite3 using node.js - node.js

I get data from a HTML form, I would like to save this data into two dependent tables.
At the moment I came up with the following node.js code:
...
db.serialize(function() {
var lastID;
db.run('INSERT INTO Idea(title,description) VALUES(?1,?2)', {
1: formData.nameText,
2: formData.ideaText
}, function(err){
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted into Idea with rowid ${this.lastID}`);
lastID = this.lastID;
console.log(`last inner ID ` + lastID);
});
db.run('INSERT INTO Places(lon,lat,IdeaID) VALUES(?1,?2,?3)', {
1: formData.lon,
2: formData.lat,
3: lastID
}, function(err){
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted with rowid ${this.lastID}`);
console.log(`IdeaID in db ` + lastID);
});
db.close();
})
The console output looks good, the database data however isn't.
The console shows:
A row has been inserted into Idea with rowid 75
last inner ID 75
A row has been inserted with rowid 16
IdeaID in db 75
Inside the database the lastID stays null.
Am I missing something? Is this the wrong way to go about it?

I solved this issue (with a phone call to my brother). Here is my solution:
db.serialize(function () {
var lastID;
db.run('INSERT INTO Idea(title,description) VALUES(?1,?2)', {
1: formData.nameText,
2: formData.ideaText
}, function (err) {
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted into Idea with rowid ${this.lastID}`);
db.run('INSERT INTO Places(lon,lat,IdeaID) VALUES(?1,?2,?3)', {
1: formData.lon,
2: formData.lat,
3: this.lastID
}, function (err) {
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted with rowid ${this.lastID}`);
});
db.close();
});
})
This works because the callback (last part of the first db.run call) is executed after the first part.
One important bit is to move the db.close(); inside the callback, otherwise the connection to the database will be closed before the part inside the callback is executed.

Related

How to query mongoDB to see if matching record exists, and if it does return it to update

Seems like a super basic task, but I just cannot get this to work (not very experienced with mongo or nodeJS).
I have an array of records. I need to check the DB to see if any records with a matching name already exist and if they do grab that record so I can update it.
Right now I am trying this
function hit_the_db(db, record_name, site_id) {
return new Promise((resolve, reject) => {
var record = db.collection('' + site_id + '_campaigns').find({name: record_name}).toArray(function(err, result) {
if (err) {
console.log('...error => ' + err.message);
reject(err);
} else {
console.log('...promise resolved...');
resolve(result);
}
});
console.log('...second layer of select successful, returning data for ' + record.length + ' records...');
return record;
});
}
This query works in another part of the app so I tried to just copy it over, but I am not getting any records returned even though I know there should be with the data I am sending over.
site_id is just a string that would look like ksdlfnsdlfu893hdsvSFJSDgfsdk. The record_name is also just a string that could really be anything but it is previously filtered so no spaces or special characters, most are something along these lines this-is-the-name.
With the names coming through there should be at least one found record for each, but I am getting nothing returned. I just cannot wrap my head around using mongo for these basic tasks, if anyone can help it would be greatly appreciated.
I am just using nodeJS and connecting to mongoDB, there is no express or mongoose or anything like that.
The problem here is that you are mixing callback and promises for async code handling. When you call:
var record = db.collection('' + site_id + '_campaigns').find({name: record_name}).toArray(function(err, result) {
You are passing in a callback function, which will receive the resulting array of mongo records in a parameter called result, but then assigning the immediate returned value to a variable called 'record', which is not going to contain anything.
Here is a cleaned up version of your function.
function hit_the_db(db, site_id, record_name, callback) {
// Find all records matching 'record_name'
db.collection(site_id + 'test_campaigns').find({ name: record_name }).toArray(function(err, results) {
// matching records are now stored in 'results'
if (err) {
console.log('err:', err);
}
return callback(err, results);
});
}
Here is optional code for testing the above function.
// This is called to generate test data
function insert_test_records_callback(db, site_id, record_name, insert_count, callback) {
const testRecords = [];
for (let i = 0; i < insert_count; ++i) {
testRecords.push({name: record_name, val: i});
}
db.collection(site_id + 'test_campaigns').insertMany(testRecords, function(err, result) {
return callback(err);
});
}
// This cleans up by deleting all test records.
function delete_test_records_callback(db, site_id, record_name, callback) {
db.collection(site_id + 'test_campaigns').deleteMany({name: record_name}, function(err, result) {
return callback(err);
});
}
// Test function to insert, query, clean up test records.
function test_callback(db) {
const site_id = 'ksdlfnsdlfu893hdsvSFJSDgfsdk';
const test_record_name = 'test_record_callback';
// First call the insert function
insert_test_records_callback(db, site_id, test_record_name, 3, function(err) {
// Once execution reaches here, insertion has completed.
if (err) {
console.log(err);
return;
}
// Do the query function
hit_the_db(db, site_id, test_record_name, function(err, records) {
// The query function has now completed
console.log('hit_the_db - err:', err);
console.log('hit_the_db - records:', records);
delete_test_records_callback(db, site_id, test_record_name, function(err, records) {
console.log('cleaned up test records.');
});
});
});
}
Output:
hit_the_db - err: null
hit_the_db - records: [ { _id: 5efe09084d078f4b7952dea8,
name: 'test_record_callback',
val: 0 },
{ _id: 5efe09084d078f4b7952dea9,
name: 'test_record_callback',
val: 1 },
{ _id: 5efe09084d078f4b7952deaa,
name: 'test_record_callback',
val: 2 } ]
cleaned up test records.

Delete last Sqlite row that have same certain name value

How can I write a function that will delete just one row (ideally the last one) that has a given name (which may not be unique).
I have tried using row count, limits, and my own built in function (below). None of these have worked.
app.delete('/FamilyMember/:db', (req, res) => {
let db = openDB("ClientsDatabases/"+req.params.db);
let ids = [];
db.serialize(()=>{
db.each('select * from family', (err, row)=> {
if (row.name == req.body.name) {
ids.push(row.id);
}
})
db.run("DELETE FROM family WHERE id = ?",ids[ids.length-1], (err)=> {
console.log("Here is the err "+err);
if (!err) console.log('Succesful # deleting', req.body.name);
});
})
res.send();
}, () => {
db.close();
})
My expected output is for only one row with the given name to be deleted, but the table doesn't change and no errors are caught.
Any particular reason you've got single quotes (') around your ? parameter in your call to Statement#run? Nothing in the API documentation suggests that this is correct practice, could be an explanation as to why your query is mangled to the point where it doesn't delete anything, but also doesn't throw an error. I'd expect your call to .run() to look something more like the below:
db.run("DELETE FROM family WHERE id = ?",ids[ids.length-1], (err)=> {
console.log("Here is the err "+err);
if (!err) console.log('Succesful # deleting', req.body.name);
});
You may alternatively be interested in simplifying your queries into a single statement that will grab the maximum id (provided the id is incremented each time) and delete that record:
db.run("DELETE FROM family WHERE id = MAX(id)", (err)=> {
console.log("Here is the err "+err);
if (!err) console.log('Succesful # deleting', req.body.name);
});
This eliminates the need to load all the contents of family first just to grab a single id from it.

Im getting SQLITE_Error: no such column, but it exists why?

Im trying to get the rowid from the database where there is someone with the same username from the guy who just wrote a message. The code works when I change
WHERE creator` =${member.username} to WHERE matchid =` ${matchid}.
It gets me the rowid from that match. But I want to get the rowids from where the user is the creator. (I checked my db and on the creator column there is the name of the username Boanak). The error that im getting is this: { Error: SQLITE_ERROR: no such column: Boanak errno: 1, code: 'SQLITE_ERROR' }.
My code:
var getMatchid = function(client, message, callback) {
//let matchid = parseInt(args.join(' '));
let member= message.member.user;
var db = new sqlite3.Database('Matches');
db.serialize(function() {
db.all(`SELECT rowid
FROM Match
WHERE creator =`+${member.username}, function(err, allRows){
if(err) {
//console.log(err);
callback(err, null);
}
else {
callback(null, allRows);
}
db.close();
});
});
}
getMatchid(client, message, function(err, data){
if (err) {
console.log(err);
}
else if (data && data.length) {
message.channel.send(`Match ${data[0].rowid} found`);
}
else {
message.channel.send("That match ID doesnt exist.");
}
});
You need to encapsulate your variable in a string. You're also using template literals, so you can put the expression directly inside.
`SELECT rowid
FROM Match
WHERE creator = "${member.username}"`

'Cannot read property 'length' of undefined' nodeJS

I'm getting started in Node.js and I'm completely confused as to why I can't get the results of my SQL query to render on a page, i'm using sqlite3.
This is a part of my index.js file
router.get('/students', function (req, res, module) {
var fs = require("fs");
var file = "./test.db";
var exists = fs.existsSync(file);
if (!exists) {
console.log("Creating DB file.");
fs.openSync(file, "w");
}
var sqlite3 = require("sqlite3").verbose();
var db = new sqlite3.Database(file);
db.serialize(function () {
if (!exists) {
db.run("Create table students ( ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, Nom varchar (255), Prenom varchar (255) );");
}
});
db.all('SELECT * FROM students', function selectCb(err, rows, fields) {
if (err) {
throw err;
}
for (var i in rows) {
console.log(rows[i]);
}
res.render('showResults.jade', {
results: rows
});
});
db.close();
res.render('students', { title: 'list' });
});
This is my Jade (create.jade) file;
block content
form(method='get', action='/students/create')
button(type='submit') Creer
ul
each item, i in results
li #{item.Nom} (#{item.Prenom})
li= JSON.stringify(item)
I put all of this things in my express app, I launch it with my shell, I receive all the sql data like this:
{ ID: 1, Nom: 'zeze', Prenom: 'zeze' }
{ ID: 2, Nom: 'ertty', Prenom: 'uuuuuuuuuuu' }
But my /students page show a message
http://i.stack.imgur.com/ormUG.png
Could you please help me, I'm really desperate.
(Sorry for my bad english I'm French) ^^
res.render('students', { title: 'list' });
and this line
each item, i in results
The variable names do not match.
From the picture, I can see that you are rendering the page called students.jade. For that page, you are sending variable title to Jade but you declared that the variable would be called results in Jade.
Have you tried removing the second res.render call?
It is possible that it is the one being called instead of the first one since the async call to the DB is not yet finished when the execution reaches the second res.render call.
db.close() should be moved inside the query's callback because it closes the db connection before the query has the chance to finish. Here is the revised code:
db.all('SELECT * FROM students', function selectCb(err, rows, fields) {
if (err) {
db.close(); // <<<<<<<<<<<<<<
throw err;
}
for (var i in rows) {
console.log(rows[i]);
}
res.render('showResults.jade', {
results: rows
});
db.close(); // <<<<<<<<<<
});

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