0

I record a JSON stream in a IndexedDB database and I can not do a search of equality with several values ​​on the same index.

My Datas :

datas = [
  {name : 'Test P1', location : 'P1'},
  {name : 'Test P1', location : 'P1'},
  {name : 'Test P2', location : 'P2'},
  {name : 'Test P2', location : 'P2'},
  {name : 'Test P3', location : 'P3'},
  {name : 'Test P3', location : 'P3'},
  {name : 'Test P3', location : 'P3'}
]

Database construction and request :

// In onupgradeneeded
var objectStore = db.createObjectStore('entreprises', {keyPath: 'id_loc'});
objectStore.createIndex("name", "name");
objectStore.createIndex("location", "location");


//In query section
var transaction = db.transaction('entreprises','readonly');
var store = transaction.objectStore('entreprises');
var index = store.index('location');
// I want select only records where location = P1 and location = P2
var request = index.openCursor(IDBKeyRange.only(['P1', 'P2']));
// Select the first matching record
var request = index.get(IDBKeyRange.only(['P1', 'P2']));

The query finds me any records. Is it possible to do that? Thank you .

3 Answers 3

2

I doubt if you can use an array with only(), API also doesn't say so, check below for IDBKeyRange.only().
Probably that's the reason it is not working for you.

The only() method of the IDBKeyRange interface creates a new key range containing a single value.

So, what you can do is open a cursor for "P1" or "P2" (whichever has lesser number of rows), and then loop through cursor to check if it contains other required value. Below is a sample I created for your handy reference, so adjust it for changes like removing hard-coded values like "location", "P1", "P2" etc.

var resultArr = [];
var keyRange = IDBKeyRange.only("P1");
cursorHandler = indexHandler.openCursor(keyRange);

cursorHandler.onerror = function(event) {
    if (errorCallBack && typeof(errorCallBack) == 'function') {
        errorCallBack(event);
    }
};

cursorHandler.onsuccess = function(event) {
    var cursor = event.target.result;
    if (cursor) {
        if(cursor.value != null && cursor.value != undefined){
            if(cursor.value["location"] == "P2"){
                resultArr.push(cursor.value);
            }
         }
        cursor["continue"]();
    } else{
        var resultObj = {"rows" : resultArr};
        if (successCallBack && typeof(successCallBack) == 'function') {
            successCallBack(resultObj);
        }
    }
    return;
};
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks i will try this, it's not too easy that Mysql request :/
Sure, let me know. BTW I couldn't understand "it's not too easy that Mysql request" ..
2

Use multi-query technique by creating cursor for each query

index.get(IDBKeyRange.only('P1')).onsuccess = cursorHandler;
index.get(IDBKeyRange.only('P2')).onsuccess = cursorHandler;

cursorHandler should store the results in sorted array by primary key.

4 Comments

What is the advantage of this approach over opening a cursor on one value and then looping it to find row matching second value. After opening 2 cursors, if in the end those results will be looped and merged to prepare final set then I don't see real advantage because merge cannot start until both cursors have finished preparing their respective result set, so the advantage of async will be lost. In fact, this approach will lead to 2 i/o operation to fetch results from database. Could you please throw light.
Result are ordered (without using in-memory buffer) with supporting limit and offset. That is common use case. BTW, your assumption on "merge cannot start until both cursors have finished" is incorrect.
Thank you for your inputs @Kyaw. I agree that results would be ordered but my doubt is around preparation of final result from 2 opened cursors. My understanding is that each cursor needs to be looped and prepare an array of results, and then a union of those 2 results sets. Could you please throw light on your approach. From YDN-DB perspective it is clean, but what's hiding behind is making me curious. And until both cursor has finished their result set preparation how the union of result set can be started?
Cursors are iterated relative to other cursors, not in the same pace nor one step at a time, by controlling cursor.continue(key), where key is computed during cursor iteration. Lastly use compound index, such as, index = store.index('location, name'); for the ordering you want.
0

Maybe try something like this:

// ...
objectStore.createIndex('locIndex',['loc1','loc2']);`
// ...
var index = store.index('locIndex');
var request = index.openCursor(IDBKeyRange.only(['P1', 'P2']));

6 Comments

IDBKeyRange.only() doesn't take an array
@AustinFrance Respectfully, IDBKeyRange does accept arrays as input.
@AustinFrance here, I went and found the specificiation description of parameters accepted by IDBKeyRange.only for you:w3.org/TR/IndexedDB/#value-construct
IDBKeyRange.only() takes a single value of type any w3.org/TR/IndexedDB/… Could that value be an array? Probably, but IDBKeyRange.only(['P1', 'P2]) is likely to match a key whose value is ['P1','P2] not match keys P1 and P2, if it was the latter the spec would say it supports an array of values to match on. The link you provided describes values that can appear in a record, not the argument types of IDBKeyRange.only()
Interestingly, IndexedDB 2.0 draft specification does appear to support value being an array. w3c.github.io/IndexedDB/#convert-a-value-to-a-key
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.