I'm creating a Windows Metro app using Visual Studio Express 2012 and an SQLite3-winrt database. My problem is that I can insert and read data from the database but I am unable to store any of the data that I have read in a local javascript variable.
function getInfo()
{
SQLite3JS.openAsync(dbPath)
.then(function (db)
{
db.runAsync('CREATE TABLE IF NOT EXISTS Resource (resourceName TEXT, resourceType TEXT, id INT PRIMARY KEY)')
return db.eachAsync('SELECT * FROM Resource', function (row)
{
console.log('Get a ' + row.resourceName + ' for' + row.resourceType);
});
})
}
The above code works fine when data is inserted in the table but I cannot do something like this:
function getInfo()
{
var rName;
SQLite3JS.openAsync(dbPath)
.then(function (db)
{
db.runAsync('CREATE TABLE IF NOT EXISTS Item (resourceName TEXT, resourceType TEXT, id INT PRIMARY KEY)')
return db.eachAsync('SELECT * FROM Resource', function (row)
{
console.log('Get a ' + row.resourceName + ' for' + row.resourceType);
rName = row.resourceName;
});
})
return rName;
}
rName ends up being undefined even if I declare it as a global variable.
I suspect it has to do with the scope. Any help would be greatly appreciated.
NB - I also tried returning rName at the line that says rName = row.resourceName but that also didn't work.
I don't have SQLite installed, but in general you want to return the result of the nested then functions. Callers then use then to get the result. Something like:
function useResults()
{
getInfo().then(function (rName) { console.log(rName); });
}
function getInfo()
{
var rName;
return SQLite3JS.openAsync(dbPath).then(function (db) {
return db.runAsync('CREATE TABLE IF NOT EXISTS Item (resourceName TEXT, resourceType TEXT, id INT PRIMARY KEY)').then(function () {
return db.eachAsync('SELECT * FROM Resource', function (row) {
console.log('Get a ' + row.resourceName + ' for' + row.resourceType);
rName = row.resourceName;
}).then(function()
{
return rName;
});
});
});
}
Although this will only effectively return the last name.
Related
I have a block of code that calls an Api and saves results if there are differences or not. I would like to return different values for DATA as layed out on the code. But this is obviously not working since Its returning undefined.
let compare = (term) => {
let DATA;
//declare empty array where we will push every thinkpad computer for sale.
let arrayToStore = [];
//declare page variable, that will be the amount of pages based on the primary results
let pages;
//this is the Initial get request to calculate amount of iterations depending on result quantities.
axios.get('https://api.mercadolibre.com/sites/MLA/search?q='+ term +'&condition=used&category=MLA1652&offset=' + 0)
.then(function (response) {
//begin calculation of pages
let amount = response.data.paging.primary_results;
//since we only care about the primary results, this is fine. Since there are 50 items per page, we divide
//amount by 50, and round it up, since the last page can contain less than 50 items
pages = Math.ceil(amount / 50);
//here we begin the for loop.
for(i = 0; i < pages; i++) {
// So for each page we will do an axios request in order to get results
//Since each page is 50 as offset, then i should be multiplied by 50.
axios.get('https://api.mercadolibre.com/sites/MLA/search?q='+ term +'&condition=used&category=MLA1652&offset=' + i * 50)
.then((response) => {
const cleanUp = response.data.results.map((result) => {
let image = result.thumbnail.replace("I.jpg", "O.jpg");
return importante = {
id: result.id,
title: result.title,
price: result.price,
link: result.permalink,
image: image,
state: result.address.state_name,
city: result.address.city_name
}
});
arrayToStore.push(cleanUp);
console.log(pages, i)
if (i === pages) {
let path = ('./compare/yesterday-' + term +'.json');
if (fs.existsSync(path)) {
console.log("Loop Finished. Reading data from Yesterday")
fs.readFile('./compare/yesterday-' + term +'.json', (err, data) => {
if (err) throw err;
let rawDataFromYesterday = JSON.parse(data);
// test
//first convert both items to check to JSON strings in order to check them.
if(JSON.stringify(rawDataFromYesterday) !== JSON.stringify(arrayToStore)) {
//Then Check difference using id, otherwise it did not work. Using lodash to help.
let difference = _.differenceBy(arrayToStore[0], rawDataFromYesterday[0],'id');
fs.writeFileSync('./compare/New'+ term + '.json', JSON.stringify(difference));
//if they are different save the new file.
//Then send it via mail
console.log("different entries, wrote difference to JSON");
let newMail = mail(difference, term);
fs.writeFileSync('./compare/yesterday-' + term +'.json', JSON.stringify(arrayToStore));
DATA = {
content: difference,
message: "These were the differences, items could be new or deleted.",
info: "an email was sent, details are the following:"
}
return DATA;
} else {
console.log("no new entries, cleaning up JSON");
fs.writeFileSync('./compare/New'+ term + '.json', []);
DATA = {
content: null,
message: "There were no difference from last consultation",
info: "The file" + './compare/New'+ term + '.json' + ' was cleaned'
}
return DATA;
}
});
} else {
console.error("error");
console.log("file did not exist, writing new file");
fs.writeFileSync('./compare/yesterday-' + term +'.json', JSON.stringify(arrayToStore));
DATA = {
content: arrayToStore,
message: "There were no registries of the consultation",
info: "Writing new file to ' " + path + "'"
}
return DATA;
}
}
})
}
}).catch(err => console.log(err));
}
module.exports = compare
So I export this compare function, which I call on my app.js.
What I want is to make this compare function return the DATA object, so I can display the actual messages on the front end,
My hopes would be, putting this compare(term) function inside a route in app.js like so:
app.get("/api/compare/:term", (req, res) => {
let {term} = req.params
let data = compare(term);
res.send(data);
})
But as I said, Its returning undefined. I tried with async await, or returning the whole axios first axios call, but Im always returning undefined.
Thank you
I'm puzzling over a weird problem I cannot replicate.
Scenario
I wrote a simple nodejs application that, after some UI interaction append some records to an Access 97 database. I'm using node-adodb to connect with it.
Some relevant piece of code.
var DBDATA = require('node-adodb'), dbConnection = DBDATA.open('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=/path/to/my/file.mdb');
function append(data, callback)
{
var table;
var query;
var array = [];
array.push({name: "Date", value: formatDate(data.date)});
array.push({name: "Time", value: formatTime(data.date)});
array.push({name: "Type", value: Number(data.Type)});
array.push({name: "Value", value: Number(exists(data.value, 0))});
// ...other fields
var fields = array.map(function (e) {
return "[" + e.name + "]";
}).join(",");
var values = array.map(function (e) {
return e.value;
}).join(",");
table = "tblData";
query = 'INSERT INTO ' + table + '(' + fields + ') ' + 'VALUES (' + values + ')';
dbConnection
.execute(query)
.on('done', function (data) {
return callback({id: id, success: true});
})
.on('fail', function (data) {
console.log(data);
return callback({id: id, success: false});
});
}
The issue
The above function is called whenever a new record is ready. Usually it works fine, but it happens about 1 time per week (among hundreds of records) that I find in the database multiple rows identical.
Due to the nature of the information this is impossible - I mean, it's impossible that the actual data is the same.
I guessed for a bug in the caller, that for some reasons sends me the same variable's content. Hence I added a check before append the record.
What I tried to do
function checkDuplicate(table, array, callback)
{
var query = "SELECT * FROM " + table + " WHERE ";
array.forEach(function(element)
{
query += "([" + element.name + "]=" + element.value + ") AND ";
});
query = query.substr(0, query.length - 4);
dbConnection
.query(query)
.on("done", function (data) {
return callback(data.records.length > 0);
})
.on("fail", function (data) {
return callback(false);
});
}
in the append function I call this one and if it returns a value > 0 I don't execute the query, because it would mean there already is the same row.
Testing it with fake data gave good results: no multiple records were added.
Unfortunately, this didn't fixed the issue in the real world. After 20 days I noticed that a row was added three times.
Questions
Do you see any evidence of a major mistake in my approach?
Is there a more reliable way to avoid this problem?
Please note I cannot change the database structure because it's not mine.
UPDATE
This is the new code I'm using:
// Add only if there isn't an identical record
query = 'INSERT INTO ' + table + '(' + fields + ') ';
query += ' SELECT TOP 1 ' + values;
query += ' FROM ' + table;
query += ' WHERE NOT EXISTS ( SELECT 1 FROM ' + table + ' WHERE ';
array.forEach(function(element)
{
query += "([" + element.name + "]=" + element.value + ") AND ";
});
query = query.substr(0, query.length - 4);
query += ' );';
dbConnection
.execute(query)
.on('done', function (data) {
return callback({id: id, success: true});
})
.on('fail', function (data) {
console.log(data);
return callback({id: id, success: false});
});
but it doesn't solved the problem, i.e. sometimes I still found two or more records identical in the database.
I'm afraid it could be the same behavior: the client make multiple requests in a while and they are executed in parallel, so each one doesn't find the record, and all will be add it.
Hance, what is the right approach to avoid this without change the database structure?
Is there a way to force node-adodb to execute only one query at time?
I am building a Phonegap application currently targeted primarily for iOS 7+.
I have a local SQLite database that I am copying clean from server. Several of the tables are empty at this time (they will not always be empty). When I use the code below, the result.insertId value is not being populated, but only for the first row inserted into the tables. After the first row all the insertIdvalues are correct.
db.transaction(function (tx1) {
tx1.executeSql(insertSQL1, [arguments],
function (t1, result1) {
if (result1 != null && result1.rowsAffected > 0) {
logMessage("Result1:" + JSON.stringify(result1));
$.each(UserSelectedArrayOfItems, function (index, value) {
db.transaction(function (tx2) {
tx2.executeSql(insertSQL2, [result1.insertId, value],
function (t2, result2) {
if (result2 != null) {
logMessage("Result2: " + JSON.stringify(result2));
}
},
function (t2, error) {
logMessage("There was an error: " + JSON.stringify(error));
});
});
});
<< Do app Navigation if all was ok >>
}
},
function (t, error) {
logMessage("Error: " + JSON.stringify(error));
});
});
While testing, both tables start empty. Zero rows. Both have an ID column with properties: INTEGER PRIMARY KEY. The insert does work and it does get an ID of 1. The ID is correct in the table, but the result.insertId is undefined in the transaction success callback.
The logMessage function writes the strings out to file so I can debug/support the app. Example log messages when inserting 1 row to parent table (always only one to parent) and 2 rows to child table (could be 1 to n rows):
Result1: {"rows":{"length":0},"rowsAffected":1}
Result2: {"rows":{"length":0},"rowsAffected":1}
Result2: {"rows":{"length":0},"rowsAffected":1,"insertId":2}
Has anyone seen this behavior before? I am using the following plugin:
<gap:plugin name="com.millerjames01.sqlite-plugin" version="1.0.1" />
Yes, I found that when you are using a value from a result (or rows) the best practice is to first evaluate the value of object to a new variable, then pass the new variable to another function call and do the work there. As an update to my example:
db.transaction(function (tx1) {
tx1.executeSql(insertSQL1, [arguments],
function (t1, result1) {
if (result1 != null && result1.rowsAffected > 0) {
logMessage("Result1:" + JSON.stringify(result1));
var newID = result1.insertId;
$.each(UserSelectedArrayOfItems, function (index, value) {
DoWork(newID, value);
});
<< Do app Navigation if all was ok >>
}
},
function (t, error) {
logMessage("Error: " + JSON.stringify(error));
});
});
function DoWork(id, value){
db.transaction(function (tx2) {
tx2.executeSql(insertSQL2, [id, value],
function (t2, result2) {
if (result2 != null) {
logMessage("Result2: " + JSON.stringify(result2));
}
},
function (t2, error) {
logMessage("There was an error: " + JSON.stringify(error));
});
});
}
You'll need to add any checks or returns so you can confirm everything went as expected. But that's the overall gist of what fixed it for me.
I am using the websql database in my webapplication to store some data from actual db and fetch it through websql api.
Currently the call is asynchronous, i.e, the result is updated after all the tasks are finished.
I want to change it to synchronous i.e, step by step executed. Here is the function i am calling from js code
function fetch(model, id, success, error) {
var tableName = model.prototype.tableName,
sql = 'SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_id = ?';
if (db) {
// websql
db.readTransaction(function (tx) {
tx.executeSql(sql, [id], function (tr, result) {
if (result.rows.length === 0) {
return null;
} else {
success(transform(model, result.rows.item(0)));
}
}, error);
});
} else {
// localStorage
throw 'Not implemented';
}
}
am calling this from a line of code.
OB.Dal.fetch(OB.Model.BusinessPartner, businessPartnerId);
How can i return the result of the method fetch() and assign it to some variable in the next step. some thing like
var bpartner = OB.Dal.fetch(OB.Model.BusinessPartner, businessPartnerId);
model.set('bp', bpartner);
--
Thanks in advance!
UPDATED CODE: i, I'm new to Javascript programming and getting an undefined variable when trying to assign a new variable from a method.
I'm using node.js and creating a redis server using the redis-client in the "client variable".
var redis = require("redis");
var client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
var numberPosts;
client.get("global:nextPostId", function(err, replies) {
numberPosts = replies;
console.log(numberPosts);
});
console.log(numberPosts);
When I call console.log inside the call back function it returns the proper value, however when I call the console.log outside of the callback function it returns "undefined". I'm trying to assign the value that is inside the callback function to the global variable numberPosts.
Any help is much appreciated, thanks.
Matt
I believe this will work:
client.get("global:nextPostId", function (err, reply) {
console.log("Number of posts: " + reply.toString());
})
The AJAX call is asynchronous so it doesn't have return value.. instead you have to use callback function and only there you have the value returned by the server method.
Edit: to assign the return value to global variable, first declare global variable:
var _numOfPosts = "";
Then:
client.get("global:nextPostId", function (err, reply) {
_numOfPosts = reply.toString());
})
However, the value won't be available until the AJAX call is finished so your original code can't work. There is not direct return value to store.
You can set timer to some reasonable response time, then have the code using the global variable in there.
Edit II: in order to call the method again once it's finished, have such code:
var _nextPostCallCount = 0;
function GetNextPost() {
//debug
console.log("GetNextPost called already " + _nextPostCallCount + " times");
//sanity check:
if (_nextPostCallCount > 1000) {
console.log("too many times, aborting");
return;
}
//invoke method:
client.get("global:nextPostId", function(err, replies) {
numberPosts = parseInt(replies.toString(), 10);
console.log("num of replies #" + (_nextPostCallCount + 1) + ": " + numberPosts);
//stop condition here.... for example if replies are 0
if (!isNaN(numberPosts) && numberPosts > 0)
GetNextPost();
});
//add to counter:
_nextPostCallCount++;
}
GetNextPost();
This will call the method over and over until the result is 0 or you pass some hard coded limit to prevent endless loop.
Try this instead to see errors:
var redis = require("redis");
client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
//note the error logging
var numberPosts = client.get("global:nextPostId", function (error, response) {
if (error) {
console.log("async: " + error);
} else {
console.log("programming: " + response);
}
});
console.log("is lotsa fun: " + numberPosts);
As Shadow Wizard has pointed out you are trying to use numberPosts before there is something in it, as client.get() hasn't returned anything.
Read this to get a handle on node.js flow:
http://www.scribd.com/doc/40366684/Nodejs-Controlling-Flow
I was facing the the same issue when I applied the MVC framework.
To solve the problem, I employed the render function.
In the posts Model
exports.get = function(id,render) {
client.incr('post:id:'+id, function(err, reply) {
render(reply);
});
};
In the posts Controller
exports.get = function(req, res) {
posts.get('001', function (data){res.render('index',{post:data});});
};