I'm implementing the Cordova Sqlite plugin in a Ionic project, so far I've been able to create a database and table and make queries following the functions available through the ngCordova implementation.
I noticed there's a insertCollection function available, which I tried to test, I passed an array to it and even though the inserts are made, the entries are made with null.
This my example table definition:
CREATE TABLE IF NOT EXISTS people (id integer primary key, firstname text, lastname text)
I filled an array like this:
for(var i = 0; i < 250000; i++){
var index = i + 1;
firstname = firstname + ' ' + index;
var entry = {
'firstname' : firstname,
'lastname' : lastname
};
$scope.insertArray.push(entry);
}
And then made the insert like this:
$cordovaSQLite.insertCollection($rootScope.db, $scope.insertQuery, $scope.insertArray).then(function(res) {
console.log(res);
}, function (err) {
console.error(err);
});
Where insertQuery is the following:
INSERT INTO people (firstname, lastname) VALUES (?,?)
I made a select like this:
$scope.select = function() {
$scope.results = [];
var query = "SELECT firstname, lastname FROM people";
$cordovaSQLite.execute($rootScope.db, query).then(function(res) {
if(res.rows.length > 0) {
console.log('select was successful ' + res.rows.length + ' entries');
for(var i = 0; i < $scope.maxItemsToShow; i++){
$scope.results.push(res.rows.item(i));
}
} else {
console.log("No results found");
}
}, function (err) {
console.error(err);
});
}
I try to display the results on a ion-list but the values in firstname and lastname are null for all the items.
What is causing this problem?
The function insertCollection expects an array of arrays, not an array of records. The inner array must contain the values to insert in the order that the question marks (as place holders for the values) appear in the sql statement.
So you need to write:
for(var i = 0; i < 250000; i++){
var index = i + 1;
firstname = firstname + ' ' + index;
var entry = [firstname, lastname];
$scope.insertArray.push(entry);
}
Related
From the npm docs, only visible prepared statements are for insert. Does these prepared statement work for Select, update, and delete?
I tried for select, there isn't a .each function where the rows are called back. Anyone been able to do this or have links to resources, cause I can sure as hell unable to find any.
According to the node-sqlite3 API documentation, you can use parameters in your SQL queries in several different ways:
// Directly in the function arguments.
db.run("UPDATE tbl SET name = ? WHERE id = ?", "bar", 2);
// As an array.
db.run("UPDATE tbl SET name = ? WHERE id = ?", [ "bar", 2 ]);
// As an object with named parameters.
db.run("UPDATE tbl SET name = $name WHERE id = $id", {
$id: 2,
$name: "bar"
});
Yes, prepared statements are supported.
With node-sqlite3:
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('data.db');
db.serialize(function() {
var stmt = db.prepare("INSERT INTO users VALUES (?,?)");
for (var i = 0; i < 10; i++) {
stmt.run("user " + i, "email " + i);
}
stmt.finalize();
stmt = db.prepare("SELECT * FROM users WHERE id=?");
stmt.each(userId, function(err, row) {
console.log(row.name, row.email);
}, function(err, count) {
stmt.finalize();
});
});
With better-sqlite3:
var Database = require('better-sqlite3');
var db = new Database('foobar.db', options);
var stmt = db.prepare("INSERT INTO users VALUES (?,?)");
for (var i = 0; i < 10; i++) {
stmt.run("user " + i, "email " + i);
}
var stmt = db.prepare('SELECT * FROM users WHERE id=?');
var row = stmt.get(userId);
console.log(row.name, row.email);
I'm trying to run a procedure which queries documents and adjusts some properties according to some rules which are decided by the parameters that I pass to the query.
function downsample(ageInDays, downsampleFactor) {
var collection = getContext().getCollection();
var responseBody = {
deleted: 0,
message: ""
};
var downsampledDocuments = [];
var count = 0;
collection.queryDocuments(
collection.getSelfLink(),
'SELECT * FROM root r ' +
'WHERE (DATEDIFF(day, r.EventProcessedUtcTime, GETDATE()) > ' + ageInDays+ 'AND r.downsamplingFactor < ' + downsampleFactor + ')' +
'OR' +
'((DATEDIFF(day, r.EventProcessedUtcTime, GETDATE()) > ' + ageInDays + ' AND r.downsamplingFactor = null )' +
'ORDER BY r.did, r.resourceType ASC',
function (err, documents, options) {
if (err) throw err;
// Check the feed and if empty, set the body to 'no docs found',
// else perform the downsampling
if (!documents || !documents.length) {
var response = getContext().getResponse();
responseBody.message = "No documents found";
response.setBody(responseBody);
} else {
// We need to take into consideration that in a lot of cases, the data will already be downsampled so we
// example: previous downsampling factor of documents: 4, if a new downsampling is performed on these docs with factor 8 then we need to
var adjustedDownSamplingFactor;
if (documents[0].downsamplingFactor == null) {
adjustedDownSamplingFactor = downsampleFactor;
} else {
adjustedDownSamplingFactor = downsampleFactor / documents[0].downsamplingFactor;
}
var aggregatedDocument = documents[0];
var documentValueSum = 0;
var documentCount = 0;
var aggregatedDocumentValue = 0;
for(doc in documents){
if(!aggregatedDocument){
aggregatedDocument = doc;
}
if(documentCount >= adjustedDownSamplingFactor || aggregatedDocument.did !== doc.did || aggregatedDocument.resourceType !== doc.resourceType){
// preparing aggregated document
aggregatedDocumentValue = documentValueSum / documentCount;
aggregatedDocument.value = aggregatedDocumentValue;
aggregatedDocument.downsamplingFactor = downsampleFactor;
//Adding the downsampled data to the Array which will be uploaded to the cosmosdb
downsampledDocuments.push(aggregatedDocument);
aggregatedDocument = null;
documentCount = 0;
documentValueSum = 0;
continue;
}
documentValueSum += doc.value;
documentCount++;
}
var response = getContext().getResponse();
tryDelete(documents);
// Call the CRUD API to create a document.
tryCreate(downsampledDocuments[count], callback);
responseBody.message = "Downsampling was succesful"
response.setBody(responseBody);
}
});
So I'm not passing any documents to the query so I don't know which partition key I would have to supply to the stored procedure. Is there any way in which I can avoid having to supply a partition key? I'm calling this stored procedure from an API but keep getting a message that I should supply a partition key.
Is there any way in which I can avoid having to supply a partition
key?
Unfortunately no. You have to supply a partition key value.
I created a small function that stores the book isbn, it's name and it's author. Everything is fine until I start to print out array. On every entery that completes the object into array, I want it to be printed one after another in new row, but this one is printing the objects from beginning every time when a new object is inserted. How do I fix this?
var books = [];
function blaBla(){
while(isbn != null || name != null || writer != null){
var isbn = window.prompt("Enter ISBN");
var name = window.prompt("Enter name of the book");
var writer = window.prompt("Enter name of the writer");
var patternString = /^[a-zA-Z]+$/;
var patternNum = /^[0-9]+$/;
if(isbn.match(patternNum)){
if(name.match(patternString)){
if(writer.match(patternString)){
books.push({
isbn: isbn,
name: name,
writer: writer
});
}
}
}
for (var i=0; i<books.length; i++){
document.write(books[i].isbn + " - " + books[i].name + " - " + books[i].writer + "</br>");
}
}
}
PS: How do I make it even more "cleaner", so when I hit cancel on prompt, it automatically stops with entering data into array, while, if i stop it on the "writer" prompt, it deletes previous entries for that object (last isbn and last name of the book)?
Thanks in advance.
You might want to give a little more context as to what this function is doing so we can help make your code cleaner as requested. I've separated the collection logic from the display logic here, and also used a while (true) loop with breaks on null or invalid inputs which will stop the collection of data.
Please note that prompt/alert boxes are a hideous way of collecting user input though (very awkward user experience). Consider using a table, input fields, and some jQuery instead to add rows and validate what the user has entered into input boxes.
var books = [];
function collectResponses() {
var patternString = /^[a-zA-Z]+$/;
var patternNum = /^[0-9]+$/;
while (true) {
var isbn = window.prompt("Enter ISBN");
if (!isbn || !isbn.match(patternNum)) {
break;
}
var name = window.prompt("Enter name of the book");
if (!name || !name.match(patternNum)) {
break;
}
var writer = window.prompt("Enter name of the writer");
if (!writer || !writer.match(patternNum)) {
break;
}
books.push({
isbn: isbn,
name: name,
writer: writer
});
}
}
function displayResponses() {
for (var i=0; i<books.length; i++){
document.write(books[i].isbn + " - " + books[i].name + " - " + books[i].writer + "</br>");
}
}
I'm trying to get the results of the following sql command in Parse.com using cloud code.
Select shop, count(1) from Membership group by shop;
Is there a way to do so? or I can only get the number of members from selecting each shop?
var query = new Parse.Query("Membership");
query.equalTo("shop",shop_id);
var promise = query.find().then(function(results){
var number_of_membership_of_one_shop = results.leng
return results;
});
Parse unfortunately doesn't support group by.
You could first select all shops and then use a count query for each shop.
var query = new Parse.Query("Membership");
query.equalTo("shop",shop_id);
var promise = query.count().then(function(count){
var number_of_membership_of_one_shop = count;
return number_of_membership_of_one_shop;
});
If this is performing too many requests, you could select all the memberships and then count them on the client, but this will have a limit of 1000 so you may need to adopt some other techniques:
var query = new Parse.Query("Membership");
query.select("shop_id");
query.limit(1000);
var storeCounts = [];
queryObject.find({
success: function (results) {
for (var i = 0; i < results.length; i++) {
var shopId = results[i].get('shop_id');
if (!storeCounts[shopId]) {
storeCounts[shopId] = 0;
}
storeCounts[shopId]++;
}
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
I write some simple app for windows 8 Metro UI with javascript. Because natural method from microsoft to use Sqlite with Javascript in Metro UI. I use 'doo' wrapper:
dooWrapper SQLite (github)
I create a method :
function addSomething(name) {
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\a_db.sqlite';
SQLite3JS.openAsync(dbPath).then(function (db) {
return db.runAsync("INSERT INTO STH (nazwa) VALUES (:name)", { name: name }).
done(function () {
console.log('Add sth : ' + name);
db.close();
}, function (error) {
if (db) {
db.close();
}
console.log('ERROR Adding sth' + error.message);
})
});
}
I get error 'database is locked' I read about this error in documentation. But I have one question is other solution to add more rows without create 'insert' function with collections argument something like that : insert (array) ? I just want to use that function n-times without this error. That's possible?
Yes,it possible...i also got this error before....For that you just need to establish the database connection once...i have used this in my app and its working fine.
If there is no need of closing your db then then open database once like..
Add this code to default.js file
var myDatabase; //Global Variable
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\db.sqlite';
//Create Table
SQLite3JS.openAsync(dbPath).then(function(db) {
myDatabase=db;
return db.runAsync('CREATE TABLE Item (name TEXT, price REAL, id INT PRIMARY KEY)');
});
Then you just need to use below code
// For Insert
return myDatabase.runAsync('INSERT INTO Item (name, price, id) VALUES ("'+ array[i].name+'", "48484", 1);
For array
var dbPromises = [];
var testArray = [];
//only for test purpose
//You can pass your array here directly
for (var a = 0; a < 300; a++) {
var obj = {
name: "Mango"+a,
price: 100+a,
id: a
};
testArray.push(obj);
}
for (var i = 0; i < testArray.length; i++) {
var query = 'INSERT OR REPLACE INTO Item (name, price, id) VALUES ("' + testArray[i].name + '",' + testArray[i].price + ',' + testArray[i].id + ')';
dbPromises.push(globalDatabase.allAsync(query));
}
WinJS.Promise.join(dbPromises).then(function () {
debugger;
}, function(err) {
debugger;
});
Above code is used only for less array size...bcz its taking too much time for insertion...
For fasst execution you should replace just below code
for (var i = 0; i < testArray.length; i++) {
var val = '("' + testArray[i].name + '",' + testArray[i].price + ',' + testArray[i].id + '),';
query = query + val;
if ((i + 1) % 300 == 0 || (i + 1) == testArray.length) {
query = query.replace(/,$/, "");
dbPromises.push(globalDatabase.allAsync(query));
query = 'INSERT OR REPLACE INTO Item (name, price, id) VALUES ';
}
}