We have an index with keys of the form:
[ dim1, dim2, dim3, ... ]
e.g. created with:
store.createIndex('coords', ['x', 'y', 'z'], {unique: false});
And we want to select a subset bounded along each dimension.
Using an key range, e.g. created with
IDBKeyRange.bound([minX, minY, minZ], [maxX, maxY, maxZ]),
will
not be sufficient. For example, the range IDBKeyRange.bound([2,2,2], [4,4,4])
includes [3,0,0] and [3,5,5] as [2,2,2] < [3,0,0] < [3,5,5] < [4,4,4]
per the definition of keys in Indexed DB
This is a subtle trap, since it appears to work in some basic cases.
We can start with a range - which handles the first dimension property, but still need to filter the results. To be most efficient, when we see any key outside the range we should skip immediately to the next possible value in key order.
Here's the basic algorithm:
- open a cursor on [minX, minY, minZ] ... [maxX, maxY, maxZ]
- for each result, check the key [x, y, z]
- if y < minY, continue with [x, minY, minZ] and go to step 2
- if z < minZ, continue with [x, y, minZ] and go to step 2
- if y > maxY, continue with [x+1, minY, minZ] and go to step 2
- if z > maxZ, continue with [x, y+1, minZ] and go to step 2
- the value is in range! use it
- continue, and go to step 2
If you're not using integer for keys, then that + 1
actually needs
to be "the next smallest key greater than" which gets tricky for floating
point values, strings or dates. Sample code provided.