11

I have a composite index of two properties on an indexeddb objectstore and wish to retrieve a cursor based on the range of both of these properties.

Here's an example object in the store :

{species: 'Oak',xcoord: 123456, ycoord: 654321}

and index :

treeStore.createIndex("treelocation", ["xcoord","ycoord"], { unique: false });

The index creation is succesful and I can see it in the Chrome developer tools, however now I'd like to open a cursor with a keyrange on both the x and y co-ordinates (which will be the extent of a map).

Searching online I can't see how to do this, and opening an index with an array of key ranges doesn't seem to work.

4
  • Have you tried IDBKeyRange.bound([lowX,lowY],[highX,highY]) ? Just a wild guess. Commented May 13, 2013 at 14:51
  • Thanks Meryn - that was it, if you'd like to post as an answer I can accept it. Commented May 14, 2013 at 8:42
  • Hmmm must be my lucky day! :) I have posted the solution as an answer. Commented May 14, 2013 at 10:07
  • See also stackoverflow.com/questions/12084177/… Commented May 16, 2013 at 15:46

3 Answers 3

8

The range suggestion is part of the answer, but even with array keys it really is just a 1-dimensional range, not a 2- (or N-) dimensional selection of the data. With your current schema you'll need to do something like this:

index.openCursor([lowX, lowY], [highX, highY]).onsuccess = function(e) {
    var cursor = e.target.result;
    if (!cursor) return; // done!

    var x = cursor.key[0], y = cursor.key[1];
    // assert(lowX <= x && x <= highX);
    if (y < lowY) {
        cursor.continue([x, lowY]);
    } else if (y > highY) {
        cursor.continue([x + 1, lowY]);
    } else {
        processRecord(cursor.value); // we got one!
        cursor.continue();
    }
};

(if coordinates are not integral, replace + 1 with an appropriate epsilon)

I've posted an example of a generalized solution to:

https://gist.github.com/inexorabletash/704e9688f99ac12dd336

Sign up to request clarification or add additional context in comments.

2 Comments

Is this still the best approach? Trying to find items in a plane that are inside of a bounding box, starts to get slow when # items is 100k+. Does adding more than 1 to x work? Something like continue([x + boundsDiff, lowY])? (sorry for necro)
As noted, the key space is one dimensional. Calling continue([x+n, /*anything*/]) will skip over any items with a first array entry less than x+n that haven't been visited yet
6

I have been told the solution is indeed IDBKeyRange.bound([lowX,lowY],[highX,highY]).

1 Comment

This will not behave as you might expect. The range IDBKeyRange.bound([2,2], [4,4]) includes values like [3,0] and [3,5] as [2,2] < [3,0] < [3,5] < [4,4] per the definition of keys (w3c.github.io/IndexedDB/#key-construct) Which is to say, you will need to do additional filtering, as this solution on its own is insufficient. e.g. if the key [x,y_less_than_min] is seen, ignore it and advance the cursor with continue([x,lowY]); if the key [x,y_greater_than_max] is seen, ignore it and advance the cursor with continue([x+1, lowY])
4

The index you created is a composite index. It is query like this:

index = objectStore.index('treelocation');
index.get([123456, 654321]); 

Alternatively, you can use two indexes for each coorrd. In my opinion it is better.

x_index = objectStore.index('xcoord'); 
y_index = objectStore.index('ycoord');
x_species = x_index.get(IDBKeyRange.only(123456)) 
y_species = y_index.get(IDBKeyRange.only(654321)) 
species = x_species.intersect(y_species); // this is result

1 Comment

Thanks Kyaw - this would be a great solution if I only wanted to retrieve records at one location, however the x and y are geographic co-ordinates and I'm looking to retrieve a range of both as one get, hence the composite index.

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.