PouchDb with SQLite, out of memory error on query - android

I have a pouch database that contains hundreds documents of 1 Mo, so the total size is ~100 Mo. It's an Android Cordova app and I'm using:
PouchDb 5.4.5
cordova-plugin-sqlite-2 1.0.4
Each document is like this:
{
data: '...', // Very long string of 1 Mo
filename: 'myFile', // Name of a file
index: 34 // An integer
}
I'd like to do a query on this db to list all documents indexed by filename and index, without retrieving data property which is heavy.
So I did a view like this:
var designDoc = {
_id: '_design/getByFilenameAndIndex',
views: {}
};
mapFunction = function(doc){
emit(doc.filename + '/' + doc.index);
}
designDoc.views['getByFilenameAndIndex'] = { map: mapFunction.toString() };
myDb.put(designDoc);
But when I try to query my db, like this:
myDb.query('getByFilenameAndIndex', {include_docs: false}).then(function(docsByFilenameAndIndex){
console.log(docsByFilenameAndIndex);
});
I get the following error:
Why I'm having this error ? I still have 900 Mo of ram available on my device (Android 6), and I'm not even including docs. If my db is less than 20 Mo it works fine.
It was working fine too with db of 40 Mo before using SQLite plugin, but I can't work without it since I need more than 50 Mo database.
Edit: I tried to do this and I get the error too: myDb.allDocs({include_docs: false});

Instead of directly inserting large binary strings into your documents, you should use attachments. These will ensure that when you do operations that don't touch attachments (such as queries, allDocs(), etc.), PouchDB won't read the attachments into memory. This should fix your Out Of Memory issues.

Related

How to retrieve data from SQLite on Android

I am working on a project that uses Ionic 1 and AngularJS. I have successfully stored data in SQLite. On the simulator of the Ionic (using ionic serve --lab) the data is displayed (console.log()) as follows:
SQLResultSetRowList {0: {…}, length: 1}
0: { // data }
length: 1
So I can get the data easily from accessing the object in the result array. However, on real mobile device (I am testing on Android), the data is displayed like this.
The problem is in here. I want to access the rows inside the Closure of that <function scope> that is inside the item: function, which I really don't know how it is generated (and I mean all of these) because the only result I want is as how I got just like in the simulator.
This is how I inserted the data.
$cordovaSQLite.execute(db, "INSERT OR REPLACE INTO token (token) VALUES (?)", [myData]).then(function (res) {
callback();
}, function (error) {
ErrorHandler.handle(error);
});
This is how I query the data.
$cordovaSQLite.execute(db, "SELECT * FROM token").then(function (res) {
console.log(res);
}, function (error) {
ErrorHandler.handle(error);
});
Anyone has an idea to solve this?
Any way is acceptable.
Okay. I have found the solution to solve this problem myself from this.
I need to use it like this.
if (res.rows.length > 0){
if (window.cordova) {
// Mobile Device
console.log(JSON.parse(res.rows.item(0)));
} else {
// Web
console.log(JSON.parse(res.rows[0]));
}
}

Delete pre-populated sqlite database when update in cordova

I have completed my project which contains a pre populated sqlite database.
I have found this plugin and it works for me nicely. Lifehelper's products are truly remarkable and they have maintain pretty nice documentation.
However, when i open database, i use this format which is suggested their documentation for pre populated database.
var db = window.sqlitePlugin.openDatabase({name: "my.db", location: 'default', createFromLocation: 1});
However, my database is only for information. Application only read data from pre populated database. There is no any insert, update or delete query to keep per any user information.
In every new version pre populated data could modified, updated by me. So I need completely new app install along with new database when user will update their app.
But unfortunately, my app could not delete previous database. Changing version code also not working.
Someone suggest me, its about location which i am using to open database. But i can not understand how should dealing with it.
Help me, best answer is more important to me. Thanks.
To avoid increasing app size, you can do something like this:
function cleanupDatabases() {
var oldDatabases = ["2.1.0.db", "2.0.0.db"];
if (window.sqlitePlugin !== undefined) {
angular.forEach(oldDatabases, function(db) {
window.sqlitePlugin.deleteDatabase({
name: db,
location: 2
}, function() {
console.log("%c " + db + " is deleted", "background: green; color: white");
}, function(error) {
console.log("%c " + db + " could not be deleted", "background: red; color: white", error);
});
});
}
};

WebView app (PhoneGap Build), not saving localStorage after restart

For some reason, when I restart my PhoneGap app - it looses the localStorage vales that were stored before! I'm saving them in the normal way:
localStorage.setItem("foo","value");
This stores it just fine. However, when you restart the app (or leave the device off for a random amount of time), it seems to randomly loose the data. I've found a heck of a lot of posts about this - but no definative answer on how to get it to be persistent in a PhoneGap Build WebView app,
Any suggestions are much welcomed!
This seems to be quite a common problem with WebView apps:
Android 2.3.6 + Phonegap + localStorage
Android - Making Webview DomStorage persistant after app closed
I can't find a solution that works with PhoneGap Build apps though
An actual example I'm using, is:
var current_id = parseInt(currentId) + 1;
localStorage.setItem("entry_"+current_id,save_string);
localStorage.setItem("entryId",current_id);
..and then to extract it (not that this is important, as the problem is with the data going missing, and not with accessing it)
for (var i = 0; i < localStorage.length; i++){
if (localStorage.key(i).match("entry_")) {
outputString += "\n" + localStorage.getItem(localStorage.key(i));
}
}
I'm wondering if maybe upgrading from PhoneGap Build cli-5.2.0 to cli-6.0.0 may help. I will do this, and give it a whirl.
I guess another option, would be to use a SQL database to locally store the device (its just a bit trickier to setup, and means re-writing my code)
UPDATE: Not the ideal solution - but I have now moved the app over to use WebSQL for the app. It was a bit tricky to get the hang of (never used it before) - but seems to do the job, and shouldn't loose the data :)
EDIT
i tried it like this and it worked:
var current_id = parseInt(currentId) + 1;
localStorage.setItem("entry_"+current_id,save_string);
localStorage.setItem("entryId",current_id);
/*
//this is for checking, what is stored in localStorage
console.log("length: " + localStorage.length);
for(var i = 0; i < localStorage.length; i++) {
console.log(localStorage.key(i));
}
*/
var myEntryIdFromStorage = localStorage.getItem("entryId");
var myItem = localStorage.getItem("entry_" + myEntryIdFromStorage);
Old answer for clarification
How do you get your localstorage?
normally you should store items like you did:
var permanentStorage = window.localstorage;
permanentStorage.setItem("foo", "bar");
and get them back by initializing the permanentStorage the same way and:
//assuming you have permanentStorage in the same script file
//or else you have to initialize it again:
//var permanentStorage = window.localstorage;
var myItem = permanentStorage.getItem("foo");
console.log("myItem: " + myItem);
The method store item uses two parameters: the identifier and the data itself. Please check, that the identifier with which you store your data is the same as the one, with which you get it back.
Do you get any errors? Is the return (stored in my example in myItem) null or undefined or just an empty string? Does this fail in the browser or on the device?
You could clarify your question by providing more code or error messages!

Android: work with Parse database for an IncrementKey column at Parse

I am working on a Android app and is using Parse Database, and would like to add a IncrementKey function such that when a new image is added to the database, the image_id column would increase itself by 1.
Reference: https://www.parse.com/questions/incrementkey
Question:
However, googled for a long while, there are no explicit example to show how to get it work... it involves cloud code at parse. Would there be any hints on how could that be done?
Thanks!
To create a beforeSave trigger for Image (replace where relevant, I've assumed this is your Class that holds the images and counter column - these are properties of the same Object)
file: ./cloud_code/cloud/main.js or a filepath required by main.js
Parse.Cloud.beforeSave("Image", function(request, response) {
//check if this is a new or existing Image
if (!request.object.isNew()) {
//image exists, save as normal
response.success();
} else {
//find the last image saved
var checkImage = Parse.Object.extend("Image");
var imagesQuery = new Parse.Query(checkImage);
imagesQuery.select("image_id"); //save memory by only requesting image_id
imagesQuery.descending("image_id"); //sort, make sure image_id is a Number
imagesQuery.first().then(
function(lastImage) {
//increase the id by 1
var newId = lastImage.get("image_id") + 1;
//save the current object with the new id
request.object.set("image_id", newId);
response.success(); //this saves your request.object
},
function (error)
response.error(error);
}
);
}
});
Resources
Cloud code guide: https://parse.com/docs/cloudcode/guide
Cloud code beforeSave modify: https://parse.com/docs/cloudcode/guide#cloud-code-modifying-objects-on-save
Retrieving objects: https://www.parse.com/docs/js_guide#objects-retrieving
Increment (updating an existing field): https://parse.com/docs/js/guide#objects-counters
See also Parse cloudcode beforeSave obtain pre-updated object (the other way around)
Read the Cloud code guide to learn how to e.g. install the CLI tools to deploy your Cloud Code and check the Cloud logs for debugging.
Disclaimer: code above is untested but based on working functions
Note: use isNew() in a beforeSave handler, existed in an afterSave handler. There's a reported bug for existed in Parse Cloud Code versions 1.6.* - see Parse request.object.existed() return false

Titanium install DB

I have some trouble with installing a database with Ti.Database.install(). Here's what I'm doing:
Open new default alloy project
Add some code to controllers/index.js so the file looks like this
var db = Ti.Database.install('/testimusDB.sqlite', 'testimusDB');
var rs = db.execute('SELECT * FROM testimusTable');
db.close();
while (rs.isValidRow())
{
var name = rs.fieldByName('name');
var age = rs.fieldByName('age');
alert(name + ' is ' + age + 'years old');
rs.next();
}
rs.close();
$.index.open();
create a DB with FF Plugin SQLite Manager called testimusDB.sqlite
and copy it to the REsources Folder of the Project
Start the App via Titanium Studio on a Samsung S3
What I get is
Runtime Error: LOCATION: [101,19] ti:/invoker.js
MESSAGE: Uncaught Error: Resources/testimusDB.sqlite SOURCE: return
delegate.apply(invoker._thisObj_,args);
People with the same problem solved it by reducing the size of the DB (mine is 64 KB) or by using absolute path (I tried absolute-/relative- path and sqlite-/db-/sql- suffix). Any ideas how to solve this problem?
Okay I got it: You can't use install() when you're using alloy! (If anybody knows an official source for this information please let me know). You need to use models to sync the database. This guy and this guide helped me a lot.
Thanks for the answers.
Close connection to db at the end of operation:
rs.close();
db.close();
Size of the database doesn't matter. I'm using much bigger one: >10MB.

Categories

Resources