I have a few tables in my SQLite database and each of them have a foreign key that tie each other.
Lets say the structure are like:
Person
=========
Id
Name
Income
=========
IncomeId
PersonId
Income
Contact
=========
ContactId
PersonId
ContactName
The PersonId in both income and contact table are foreign key to the Person table.
Now when i want to query out the data from all the tables, first i select from Person, then in the callback, i will loop through the data, and select from Income and Contact for each of the record. I can't do a join select as the data are not mandatory, i.e. for a Person it might have income but not contact, or vice versa.
However when i try to run through the loop, i found that the result is always the last instance of the data. After some googling the issue seems to be that i need to use Closure.
I tried to implement it but is having a hard time, currently my code looks like this:
for (var i = 0; i < len; i++){
var profile= results.rows.item(i);
var IdAir = profile["IdAir"];
console.log('processing AIR Id: ' + IdAir);
function queryIncomeSuccess(tx,incomeAirResult, currentLoop){
var lenIncomeAir = incomeAirResult.rows.length;
var incomeAIR = {};
if(lenIncomeAir > 0){
incomeAIR = incomeAirResult.rows.item(0);
}else{
incomeAIR = null;
}
if(currentLoop == len - 1)
{
profile["Income"] = incomeAIR ;
airJson[airJson.length] = profile;
}
};
function queryIncome(tx) {
tx.executeSql("SELECT * FROM Income WHERE IdAir = ?",
[IdAir], function(resultSet){
queryIncomeSuccess(tx,resultSet,i);
}, errorCB);
};
db.transaction(queryIncome, errorCB);
}
Is there any guide for multiple select for Cordova? Any help is greatly appreciated. Thanks.
Am able to get this done by using nested function and closure.
The thing to note is that, the closure need to apply at the db.transaction function, rather than on the success callback only.
Code structure used:
//inside for loop of first select result
for (var i = 0; i < len; i++){
function buildSuccessCallback(current,profile){
return function(tx, result){
querySuccess(tx, result,current,profile);
};
}
function querySuccess(tx,result,currentIdx,profile){
//...perform logic
console.log('currentIdx: ' + currentIdx); //returning the correct value
console.log('current Id: ' + profile["IdAir"]); //returning the correct Id
}
db.transaction((function(i,profile){
return function(tx){
tx.executeSql(mySQL, [profile["IdAir"]], buildSuccessCallback(i,profile), errorCB);
};
})(i,profile), errorCB);
}
Thanks.
Related
I have an issue related to database. I am currently working with Gupshup bot programming. There are two different data persistence modes which can be read here and here. In the advanced data persistence, the following code is documented to put data into data base:
function MessageHandler(context, event) {
if(event.message=='update bug - 1452') {
jiraUpdate(context);
}
}
function jiraUpdate(context){
//connect to Jira and check for latest update and values
if(true){
context.simpledb.doPut("1452" ,"{\"status\":\"QA pending\",\"lastUpdated\":\"06\/05\/2016\",\"userName\":\"John\",\"comment\":\"Dependent on builds team to provide right build\"}");
} else{
context.sendResponse('No new updates');
}
}
function DbPutHandler(context, event) {
context.sendResponse("New update in the bug, type in the bug id to see the update");
}
If I want to change only one of column (say status or last Updated) in the table for the row with key value 1452, I am unable to do that. How can that be done?
I used the following code:
function MessageHandler(context, event) {
// var nlpToken = "xxxxxxxxxxxxxxxxxxxxxxx";//Your API.ai token
// context.sendResponse(JSON.stringify(event));
if(event.message=='deposit') {
context.sendResponse("Enter the amount to be deposited");
}
if(event.message=="1000") {
jiraUpdate(context);
}
if(event.message== "show"){
context.simpledb.doGet("1452");
}
}
function HttpResponseHandler(context, event) {
var dateJson = JSON.parse(event.getresp);
var date = dateJson.date;
context.sendResponse("Today's date is : "+date+":-)");
}
function jiraUpdate(context){
//connect to Jira and check for latest update and values
if(true){
context.simpledb.doPut("aaa" ,"{\"account_number\":\"90400\",\"balance\":\"5800\"}");
} else{
context.sendResponse('No new updates');
}
}
/** Functions declared below are required **/
function EventHandler(context, event) {
if (!context.simpledb.botleveldata.numinstance)
context.simpledb.botleveldata.numinstance = 0;
numinstances = parseInt(context.simpledb.botleveldata.numinstance) + 1;
context.simpledb.botleveldata.numinstance = numinstances;
context.sendResponse("Thanks for adding me. You are:" + numinstances);
}
function DbGetHandler(context, event) {
var bugObj = JSON.parse(event.dbval);
var bal = bugObj.balance;
var acc = bugObj.account_number;
context.sendResponse(bal);
var a = parseInt (bal,10);
var b = a +1000;
var num = b.toString();
context.simpledb.doPut.aaa.balance = num;
}
function DbPutHandler(context, event) {
context.sendResponse("testdbput keyword was last put by:" + event.dbval);
}
Since the hosted DB that is provided by Gupshup is the DynamoDB of AWS. Hence you can enter something as a key, value pair.
Hence you will have to set the right key while using doPut method to store data into the database and use the same key to get the data from the database using the doGet method.
To update the data you should first call doGet method and then update the JSON with right data and then call doPut method to update the database with the latest data.
I have also added something which is not present in the documentation, You can now make DB calls and choose which function the response goes to.
I am refactoring your example as using 3 keywords and hard coding few things just for example -
have - this will update the database with these values
{"account_number":"90400","balance":"5800"}
deposit - on this, the code will add 1000 to the balance
show - on this, the code show the balance to the user.
Code -
function MessageHandler(context, event) {
if(event.message=='have') {
var data = {"account_number":"90400","balance":"5800"};
context.simpledb.doPut(event.sender,JSON.stringify(data),insertData); //using event.sender to keep the key unique
return;
}
if(event.message=="deposit") {
context.simpledb.doGet(event.sender, updateData);
return;
}
if(event.message== "show"){
context.simpledb.doGet(event.sender);
return;
}
}
function insertData(context){
context.sendResponse("I have your data now. To update just say \"deposit\"");
}
function updateData(context,event){
var bugObj = JSON.parse(event.dbval);
var bal = bugObj.balance;
var a = parseInt(bal,10);
var b = a + 1000;
var num = b.toString();
bugObj.balance = num;
context.simpledb.doPut(event.sender,bugObj);
}
function EventHandler(context, event) {
if (!context.simpledb.botleveldata.numinstance)
context.simpledb.botleveldata.numinstance = 0;
numinstances = parseInt(context.simpledb.botleveldata.numinstance) + 1;
context.simpledb.botleveldata.numinstance = numinstances;
context.sendResponse("Thanks for adding me. You are:" + numinstances);
}
function DbGetHandler(context, event) {
var accountObj = JSON.parse(event.dbval);
context.sendResponse(accountObj);
}
function DbPutHandler(context, event) {
context.sendResponse("I have updated your data. Just say \"show\" to view the data.");
}
related questions(not working):
scope-troubles-in-javascript-...
Pass extra parameters to WebSQL callback function?
I have a 'log' object to capture a few success or error variables as the websql transaction loops through the queries. There is a loop in a loop that is cycling through the data input which is provided from the server in the form of objects in arrays in objects, basically tables then rows. This all works fine until the internal success callback of the sql-query (not the final transaction success.) is called. as you can see from the below i've tried to call a function builder function to capture the table name variable but it is undefined when the returned function is called. I have tried many ways but i either end up with undefined or the last tables entries only.
I have tried to simplify my code below to focus on the issue, some of the code may be messy.I understand why its not available due to asynchronicity but not how to get around it.
addServData = function(data){
var columns, colCount, rowCount, Q, Qmks, table,
rows, dataWatch = {success:{},error:{}};
/*var tableName; //<-- MOVED THIS INTO LOOP AS THOUGHT WAS THE PROBLEM*/
oDb.transaction(function(tx){
for(var key in data){
var tableName = key;
table = data[key];
rows = table.data;
columns = table.columns;
colCount = table.colLen;
rowCount = table.rowLen;
if(rowCount <= 0) continue;
...
Q = 'BUILD QUERY.... (?,?,?)';
for(var x = rows.length-1; x >=0; x--){
var $i = rows.length - (x+1);// <-- INVERT COUNTER
//sort row object to array in order of colums;
var row = rows[$i],
params = utils.sortObjtoArr(row, columns);
tx.executeSql(Q, params,
buildCallback(tblName),
function(tx,error){
console.log('error: ', tx,error);
dataWatch.error[tblName + '::' + params[0]] = error;
});
}
}
function buildCallback(tbl){
//console.log('buildcallback'+tblName, tx); //PRINTS CORRECT NAME;
return function(tx,success,tbl){
console.log('success: ', tx, success, 'tblN:',tbl);//TBL = UNDEFINED;
dataWatch.success[tbl + '::' + success.insertId] = success.rowsAffected;
dataWatch.added += parseInt(success.rowsAffected);
}
}
}, function(tx,error){
console.log(error, dataWatch);
},
function(tx,success){
console.log('success', dataWatch); //WORKS
});
}
A standard oversight on my part, confused myself.
Turns out, in my callback builder, i was trying to retrieve the tbl variable from the sql-queries success caller function not from the scope of the callback builder!
call back should have been:
function buildCallback(tbl){
// return function(tx,success,tbl){ <-- NOT THIS;
return function(tx,success){ // <-- THIS;
console.log('success: ', tx, success, 'tblN:',tbl);//tbl = 'TABLE NAME';
.....
}
}
i am quiet new to java script and node js.
i have a problem with a simple function that i call, and it gets done more than one time.
this is my code
app.post('/checkGetSensorIds', function (req, res) {
var tables=['temperature', 'pressure', 'linear_acceleration'];
var ids= [1];
DButils.checkAllSensorsForId(connection, 1 , tables , function(idHasSensorsInfo){
console.log("idHasSensorsInfo is: \n" , idHasSensorsInfo);
});
res.end();
});
/*this function gets a user Id, and the table of all sensors the customer wants, and return true if this
user id has information in all the sesnsor tables that were requested, otherwise returns false*/
exports.checkAllSensorsForId= function(dbConnection, id , sensorsTables, callback){
var sensorsTablesLength= sensorsTables.length;
for (var i = 0; i < sensorsTables.length; i++) {
var tableName= sensorsTables[i];
DButils.checkSingleSensorForId(dbConnection, id, tableName, function(idHasSensorInfo){
if(idHasSensorInfo == false){
callback(false);
return;
}
//in case user have all info in db, we get here and need to return false
if(i == sensorsTablesLength){
callback(true);
return;
}
});
}
};
/*this function gets a user Id, and a single sensor table, and returns true if the user has information
in the requested sensor table, otherwise returns false*/
exports.checkSingleSensorForId= function(dbConnection , id , sensorTable, callback){
var myQuery = 'SELECT count(*) as IdCount FROM ' + sensorTable + ' WHERE id= ' + id;
var query = dbConnection.query(myQuery, function (err, row, result) {
console.log(query.sql);
if (err) {
console.log("checkSingleSensorForId error");
console.error(err);
return;
}
var count= row[0].IdCount;
var idHasSensorInfo = (count > 0);
callback(idHasSensorInfo);
});
};
console.log("idHasSensorsInfo is: \n" , idHasSensorsInfo); is a line that invoked 3 times, while should be only once.
someone has any idea why, and what i need to do to fix it?
You have this line:
DButils.checkAllSensorsForId(connection, 1 , tables , function(idHasSensorsInfo){
console.log("idHasSensorsInfo is: \n" , idHasSensorsInfo);
});
Then you have this:
exports.checkAllSensorsForId= function(dbConnection, id , sensorsTables, callback){
...
for (var i = 0; i < sensorsTables.length; i++) {
...
callback();
...
}
};
So the callback line will be invoked as many times as you call it, which in your case is probably 3 - all it does is call the function from above, so thats why you see it invoked 3 times.
I'm not sure exactly what you are trying to do, but if the callback should be only called once, make sure its ran only once - if it should 'cancel' the for - add a condition to the for or use a promise to resolve whenever you are ready.
DEMO
I am unable to retrieve third value of the row it is showing undefined when displayed using alert box .What i am basically trying to achieve is insert 4 rows to table and retrieve them as required sorted based on a column
HTML
<div id="status" name="status">Status Message</div>
Javascript
var db = openDatabase('mydb', '1.0', 'Test DB', 4 * 1024 * 1024);
var msg;
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log Text,log1 Text)');
tx.executeSql('INSERT INTO LOGS (id, log,log1) VALUES (1, "foobar","sa")');
tx.executeSql('INSERT INTO LOGS (id, log,log1) VALUES (2, "logmsg","da")');
msg = '<p>Log message created and row inserted.</p>';
document.querySelector('#status').innerHTML = msg;
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
var len = results.rows.length,
i;
msg = "<p>Found rows: " + len + "</p>";
document.querySelector('#status').innerHTML += msg;
for (i = 0; i < len; i++) {
msg = "<p><b>" + results.rows.item(i).log + "</b></p>";
document.querySelector('#status').innerHTML += msg;
var book = results.rows.item(i);
console.log(book);
alert(book.log1);
}
}, null);
});
here i make something very similar to yours, and here it's working. Here my Ids are like:
id integer primary key
So when I do an insert, I don't have to use them, I let web sql take care of it
tx.executeSql('INSERT INTO LOGS (log,log1) VALUES ("logmsg","da")');
Also, I use promises (the code bellow is using angularJs
self.query = function(query, bindings) {
bindings = typeof bindings !== 'undefined' ? bindings : [];
var deferred = $q.defer();
self.db.transaction(function(transaction) {
transaction.executeSql(query, bindings, function(transaction, result) {
deferred.resolve(result);
}, function(transaction, error) {
deferred.reject(error);
});
});
return deferred.promise;
};
self.fetchAll = function(result) {
var output = [];
for (var i = 0; i < result.rows.length; i++) {
output.push(result.rows.item(i));
}
return output;
};
self.fetch = function(result) {
return result.rows.item(0);
};
So I can use it this way:
return DB.query('SELECT * FROM registro WHERE dia = ? and mes = ? and ano = ? order by horario', [dia, mes, ano])
.then(function(result){
return DB.fetchAll(result);
});
I hope this can get you some directions...
Your DEMO link works fine for me (with Chrome 39) - I'm getting 'sa', 'da' alerts after running it. So I think it's something specific to your browser or more probably your cache.
Have you maybe created LOG table without the log1 column at first? Maybe it's still stored in your browser, because
CREATE TABLE IF NOT EXISTS LOGS (id unique, log Text,log1 Text)
line is not going to override it.
In Chrome you can check WebSQL schema hold by the browser with ChromeDevTools and 'Resources' tab, take a look there and see if mydb/LOGS table have your log1 column and data in it.
I'm really new to node.js and having a bit of a problem with objects. Lets say I have two files, one called printer.js and another called database.js. printer.js prints the results database returns. printer.js looks like this:
var db = require("./database")
db.getStations(dbReturn);
function dbReturn(stations) {
for(var i = 0; i < stations.length; i++) {
console.log('id: ' + stations.id);
}
}
and my database.js looks like this:
function getStations(callback){
var listOfStations = [];
for(var index = 0; index < 10; index++) {
var station = new Station(index);
listOfStations[index] = station;
}
callback(listOfStations);
}
function Station(id){
this.id = id;
}
exports.getStations = getStations;
I would just like to mention that Station class has a lot more members than that. But the problem here is that I cannot access the members from the Station objects I created in database.js from printer.js. I am having quite a bit of trouble figuring out how to do this. I have learned how to create a new object of Station in printer.js by exporting Station, but I still can't access the members of an object I created somewhere else! It just spits out 10 x "id: undefined"
I have been suggested to do something similar to this:
database.prototype.getStations = function(callback) {
//...
}
database.prototype.Station = function(id) {
//...
}
module.exports = database;
But this does not seem to work since it just tells me that database is undefined. What am I doing wrong here?
You're not accessing the stations by index in your for loop.
Change this in printer.js:
console.log('id: ' + stations.id);
to:
console.log('id: ' + stations[i].id);