Sorting the results of an indexedDB query - javascript

I want to sort results obtained from indexedDB.
Each record has structure {id, text, date} where 'id' is the keyPath.
I want to sort the results by date.
My current code is as below:
var trans = db.transaction(['msgs'], IDBTransaction.READ);
var store = trans.objectStore('msgs');
// Get everything in the store;
var keyRange = IDBKeyRange.lowerBound("");
var cursorRequest = store.openCursor(keyRange);
cursorRequest.onsuccess = function(e) {
var result = e.target.result;
if(!!result == false){
return;
}
console.log(result.value);
result.continue();
};

Actually you have to index the date field in the msgs objectStore and open an index cursor on the objectStore.
var cursorRequest = store.index('date').openCursor(null, 'next'); // or prev
This will get the sorted result. That is how indexes are supposed to be used.

Here's the more efficient way suggested by Josh.
Supposing you created an index on "date":
// Use the literal "readonly" instead of IDBTransaction.READ, which is deprecated:
var trans = db.transaction(['msgs'], "readonly");
var store = trans.objectStore('msgs');
var index = store.index('date');
// Get everything in the store:
var cursorRequest = index.openCursor();
// It's the same as:
// var cursorRequest = index.openCursor(null, "next");
// Or, if you want a "descendent ordering":
// var cursorRequest = index.openCursor(null, "prev");
// Note that there's no need to define a key range if you want all the objects
var res = new Array();
cursorRequest.onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
res.push(cursor.value);
cursor.continue();
}
else {
//print res etc....
}
};
More on cursor direction here: http://www.w3.org/TR/IndexedDB/#cursor-concept
IDBIndex API is here: http://www.w3.org/TR/IndexedDB/#idl-def-IDBIndex

Thanks to zomg, hughfdjackson of javascript irc, I sorted the final array. Modified code as below:
var trans = db.transaction(['msgs'], IDBTransaction.READ);
var store = trans.objectStore('msgs');
// Get everything in the store;
var keyRange = IDBKeyRange.lowerBound("");
var cursorRequest = store.openCursor(keyRange);
var res = new Array();
cursorRequest.onsuccess = function(e) {
var result = e.target.result;
if(!!result == false){
**res.sort(function(a,b){return Number(a.date) - Number(b.date);});**
//print res etc....
return;
}
res.push(result.value);
result.continue();
};

Related

How to get the value of an array inside an array?

I have to take each data of the array inside an array but it doesn't work when I use something like tmp.name or tmp[0].name would result undefined and even tmp.length result 0
var tmp = [];
var db = firebase.firestore();
var docCollection = db.collection('doctors');
var assignedDoctors = docCollection.where('assign', '==', user.key).get();
assignedDoctors.then(function(doc){
let i = 0;
doc.forEach(function(md){
tmp.push(md.data());
tmp[i].key = md.id;
i++;
});
}).catch(function(e){
console.log(e);
});
console.log(tmp)
the tmp result
[]
0: {assign: "userA", name: "NameA"}
1: {assign: "userA", name: "NameB"}
length: 2
__proto_: Array(0)
Just declare map and assign all data of md.data() to map and then push map into array and remove variable i as no need of it. Like following:
doc.forEach(function(md){
var map = {};
map = md.data();
map.key = md.id;
tmp.push(map);
});
var tmp = [];
var db = firebase.firestore();
var docCollection = db.collection('doctors');
var assignedDoctors = docCollection.where('assign', '==', user.key).get();
assignedDoctors.then(function(doc){
let i = 0;
doc.forEach(function(md){
tmp.push(md.data());
// tmp[i].key = md.id;
// i++;
});
}).catch(function(e){
console.log(e);
});
console.log(tmp)
comment these line and check it.

Javascript stored only the last one from a loop in an JSON Object

I have a HTML Site with 4 inputRange slidern. If a user click on a button all the values from the ranges should be stored in a nested JSON Object. So far so good, but JS only saves the last one in that Array and not the others before.
But all Sliders have different values from 1 to 5, but JS saves only the 4 from the last slider. Here's my code:
//Speichert die aktuellen Angaben in einem Nested-JSON Objekt
function saveBewertung() {
var jsonObj = {};
var kriterien = [];
var bewertungen = {};
//Loop
$('input[type=range]').each(function() {
var id = $(this).attr("id");
var note = $(this).val();
bewertungen.id = id;
bewertungen.note = note;
kriterien.push(bewertungen);
jsonObj.Bewertungen = kriterien;
});
jsonObj.Kommentar = $('textarea#kommentar').val();
//TEST AUSGABE
alert(JSON.stringify(jsonObj));
}
Result:
You are pushing the same object to the array again and again. You need to initialize bewertungen every time in the each block.
Declare
var bewertungen = {};
inside the each block
$('input[type=range]').each(function() {
var bewertungen = {};
var id = $(this).attr("id");
var note = $(this).val();
bewertungen.id = id;
bewertungen.note = note;
kriterien.push(bewertungen);
});
jsonObj.Bewertungen = kriterien; //this line can be moved out
Another possibility next to the solution from #gurvinder372 is to shorten the function so you don't need to declare the variables bewertungen, id and note:
//Speichert die aktuellen Angaben in einem Nested-JSON Objekt
function saveBewertung() {
var jsonObj = {};
var kriterien = [];
//Loop
$('input[type=range]').each(function() {
// Anonymous object
kriterien.push({
id: $(this).attr("id"),
note: $(this).val()
});
});
jsonObj.Bewertungen = kriterien;
jsonObj.Kommentar = $('textarea#kommentar').val();
//TEST AUSGABE
alert(JSON.stringify(jsonObj));
}
Here is some description how this thing is working
var bewertungen = {}; // this line declare the object this object will hold values in each loop.
$('input[type=range]').each(function() {
var bewertungen = {};
var id = $(this).attr("id");
var note = $(this).val();
bewertungen.id = id; // this line add value to {bewertungen} object key
bewertungen.note = note; // this line add value to {bewertungen} object key
kriterien.push(bewertungen); // every itration will push value to [kriterien] array
});
jsonObj.Bewertungen = kriterien; // this is final array with all values

Working with cursors in Indexed DB

Below is my indexeddb(IDB) objectStore name and its calling method.
What I want is get the values from objectStore and based on condition matched values add those values calculation into Variable.
var item_id = [];
var db;
function displayNotes(filter) {
var line = 0;
var transaction = db.transaction(["frp_item_master"], "readonly");
var itemsname =[];
var itemsqty =[];
var itemsprice =[];
var itemsdisc =[];
var itemstax =[];
var handleResult = function(event) {
var cursor = event.target.result;
var price_with_tax;
var i = 0;
i++;
if (cursor) {
++line;
if (cursor.value.item_id == 20008)
{
item_id.push(event.target.result.value.item_id);
//and other array push here
//call function
price_with_tax = (get_tax(itemstax)/100)*itemsprice;
}
cursor.continue();
}
else {
//error
}
};
Then after creating my function which is called in above method.
function get_tax(p_tax_master_id){
var get_me;
var total_tax_rate = 0;
var transaction = db.transaction(["frp_tax_master"], "readonly");
var objectStore = transaction.objectStore('frp_tax_master');
objectStore.openCursor().onsuccess = function(event){
var cur = event.target.result;
get_me = event.target.result.value.tax_master_id;
console.log('get_me'+get_me);
if (cur) {
if (get_me == 2008)
{
total_tax_rate += event.target.result.value.rate;
console.log("total tax"+total_tax_rate);
}
cur.continue();
}
else {
console.log('else'+get_me);
}
};
return total_tax_rate;
};
I am getting errors as shown in images. Cursor is still running even if there no value into the object store and it shows Value can not be set to null.
Can we just loop through all records and till last values are fetched then exit from cursor assign that values to the variable.
Basically I am adding some number to a variable.
screenshot-1
screenshot-2
In this line you get the cursor:
var cur = event.target.result;
And here you correctly check that the cursor is not null before using it:
if (cur) {
But this line assumes that event.target.result is not null:
get_me = event.target.result.value.tax_master_id;
So when the cursor hits the end of its range, event.target.result is null which gives you the "can't read property 'value' of null" error on the exact line the console is telling you.
Consider moving that line into the if (cur) block.
In addition to what Joshua said, the onsuccess method is asynchronous, so your get_tax function will always return 0.
Consider something like:
function get_tax(p_tax_master_id, cb) {
var get_me;
var total_tax_rate = 0;
var transaction = db.transaction(["frp_tax_master"], "readonly");
var objectStore = transaction.objectStore('frp_tax_master');
objectStore.openCursor().onsuccess = function(event){
var cur = event.target.result;
console.log('get_me'+get_me);
if (cur) {
get_me = event.target.result.value.tax_master_id;
if (get_me == 2008) {
total_tax_rate += event.target.result.value.rate;
console.log("total tax"+total_tax_rate);
}
cur.continue();
} else {
console.log('else'+get_me);
cb(null, total_tax_rate);
}
};
};
You might also prefer to use a library such as ZangoDB so you could perform a query like:
var db = new zango.Db('db_name', ['frp_tax_master']);
var frp_tax_master = db.collection('frp_tax_master');
function get_tax(p_tax_master_id, cb) {
frp_tax_master.find({
tax_master_id: 2008
}).group({
total_tax_rate: { $sum: '$rate' }
}).toArray((error, docs) => {
if (error || !docs[0]) { cb(error); }
else { cb(null, docs[0].total_tax_rate); }
});
}

Why ScriptDb query result object is different

function myFunction() {
var item = {};
item = {id:'myId', rules: {1:'rule1', 2:'rule2'}};
Logger.log(item); // {id=myId, rules={2=rule2, 1=rule1}}
Logger.log(item.rules[1]); // rule1
var db = ScriptDb.getMyDb();
db.save(item);
var result = db.query({id:'myId'});
item = result.next();
Logger.log(item); // {id=myId, rules={2=rule2, 1=rule1}}
Logger.log(item.rules[1]); // undefined, why?
}
Expecting the last log to return the value "rule1" like in the original object.
Why is it now undefined?
A strange case, it may be a bug.
With the following code can get what you need:
...
item = JSON.parse(item.toJson());
Logger.log(item); // {id=myId, rules={2=rule2, 1=rule1}}
Logger.log(item.rules[1]); // rule1
...
An alternative route for storing and filtering results with a numerical value instead of with a numerical key.
function myFunction() {
var db = ScriptDb.getMyDb();
var item1 = {id:'myId', rule:{num:1, details:'rule1'}};
var item2 = {id:'myId', rule:{num:2, details:'rule2'}};
var saveResults = db.saveBatch([item1, item2], false);
var results = db.query({id:'myId'});
while (results.hasNext()) {
var item = results.next();
if (item.rule.num == 1)
Logger.log(item.rule.details); // rule1
}
}

How do I iterate over an IndexedDB objectStore using a condition on a non-key property?

I have a select box that I want to populate automatically with values from a objectStore, for that I need to iterate it like this: "Select COL1 from TABLE where COL2 = 'myvalue'",
this is my code:
var db;
var req = indexedDB.open("DB");
req.onsuccess = function (e) {
db = req.result;
var tran = db.transaction("store");
var singleKeyRange = IDBKeyRange.only("myvalue"); //the value I want to reach from COL2
tran.objectStore("store").openCursor(singleKeyRange).onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
var opt = document.getElementById("selectbox");
var option = document.createElement("option");
var optionText=document.createTextNode(cursor.value.COL1); //the matching values in COL1
option.appendChild(optionText);
opt.appendChild(option);
cursor.continue();
}
}
};
I have all my values correctly indexed in the objectStore, just don't now how to reach values through others values.
Here is an example in which items are searched on non-indexed column, you need to go through all items and compare the values and add them to list, after that you can return the result set.
function SearchItems( keyPath, value, requestNo, callback){
var initOpenReq = indexedDB.open(baseName);
initOpenReq.onsuccess = function() {
var db = initOpenReq.result;
var transaction = db.transaction(objectStoreName, 'readonly');
var objectStore = transaction.objectStore(objectStoreName);
var cursorRequest = objectStore.openCursor();
var agregate = [];
cursorRequest.onsuccess = function (event){
if (event.target.result){
if(event.target.result.value[keyPath] && event.target.result.value[keyPath] == value){ //compare values
agregate.push(event.target.result.value);
}
event.target.result['continue']();
}
};
transaction.oncomplete = function (event) {
callback(agregate); // return items
};
}
}
This is an example with an index.
var db;
var req = indexedDB.open("DB", 2);
// Creating the index
req.onupgradeneeded = function (e){
var trans = e.target.transaction;
var obj = trans.objectStore("store");
obj.createIndex("indexname", "keypath") // keypath is the propertyname you want the index on. for Ex. {Name: "x", Age:5 }; If you want to filter on Name, keypath = Name
}
req.onsuccess = function (e) {
db = req.result;
var tran = db.transaction("store");
var singleKeyRange = IDBKeyRange.only("myvalue"); //the value I want to reach from COL2
var objectStore = tran.objectStore("store");
var opt = document.getElementById("selectbox");
objectStore.index("indexname").openCursor(singleKeyRange).onsuccess =
function(e){
var cursor = e.target.result;
if (cursor) {
var option = document.createElement("option");
var optionText=document.createTextNode(cursor.value.COL1); //the matching values in COL1
option.appendChild(optionText);
opt.appendChild(option);
cursor.continue();
}
}
};

Categories