IndexedDB: IDBKeyRange.forPrefix

420 views
Skip to first unread message

Joshua Bell

unread,
Oct 7, 2013, 7:41:49 PM10/7/13
to Chromium HTML5
When discussing incremental additions to the Indexed DB API with some other browser vendors, the need for an API that would yield an IDBKeyRange for a given prefix was brought up.

e.g. if you're using an object store to represent a file system, you might have keys of the form:

"/tmp/a
"/tmp/dir/b"
"/tmp/dir/c"
"/tmp/dir2/d"
"/tmp/e"

If you want to iterate over everything in "/tmp/dir" you need to construct a key range for everything with prefix "/tmp/dir/". Constructing such a key range requires somewhat intricate knowledge of JS strings and IDB keys. We talked about adding an API such as:

IDBKeyRange.forPrefix(key)

This is something that can be "prollyfilled" today, so to get feedback before we add it to the platform I spun up a basic implementation:


Although strings keys are the obvious case, I tackled numbers and dates and arrays as well. Arrays raised some interesting edge cases, so I'd appreciate feedback. Is this useful? Does it meet your expectations? Do you have use cases beyond string keys? Is this something where a platform addition makes sense, or is the use case too limited?

Kyaw

unread,
Oct 14, 2013, 12:53:50 PM10/14/13
to chromiu...@chromium.org
It is very useful and killer feature to fully utilise indexeddb key. As you see, this lead to prefix base key filter query, which is very efficient.

Regarding array prefix, I let upper bound of [IDBKey], to be [IDBKey, '\uffff']. The main use cases of array prefix are hierarchical key and prefix-filtered compound key joining.

Parent-child relationship can be constrained by using hierarchical key, in which child primary key is [parentKey, uniqueChildId]. In this way, an parent record can query its child objects by IDBKeyRange.starts([parentKey]).  

Prefixing compound (array) index is useful for equal AND query. For example, to find all records of 'index1' = 'A' and 'index2' = 'B', we can open two cursors, index1 with IDBKeyRange.starts(['A']) and index2 with IDBKeyRange.starts(['B']).  

BTW, what are the use for number and date?

I prefer the function name to be, IDBKeyRange.startsWith or simply IDBKeyRange.starts. 
    
My implementation is simply:

ydn.db.KeyRange.starts = function(value) {
  var value_upper;
  if (goog.isArray(value)) {
    value_upper = goog.array.clone(value);
    // Note on ordering: array > string > data > number
    value_upper.push('\uffff');
  } else if (goog.isString(value)) {
    value_upper = value + '\uffff';
  } else {
    return ydn.db.KeyRange.only(value);
  }

  return ydn.db.KeyRange.bound(value, value_upper, false, true);
};

Which work fine. But platform implementation is better to cover conner cases, as you said.

Joshua Bell

unread,
Oct 15, 2013, 5:59:36 PM10/15/13
to Kyaw, Chromium HTML5
On Mon, Oct 14, 2013 at 9:53 AM, Kyaw <kya...@yathit.com> wrote:
It is very useful and killer feature to fully utilise indexeddb key. As you see, this lead to prefix base key filter query, which is very efficient.

Regarding array prefix, I let upper bound of [IDBKey], to be [IDBKey, '\uffff']. The main use cases of array prefix are hierarchical key and prefix-filtered compound key joining.


My general approach for the (exclusive) upper bound given [k] was [successor(k)] ... which breaks down if k is an empty array and has no successor.

If your schema is such that don't use arrays as "primitive" key values, only for "key structure" (I'm sure there are formal names for this stuff), then you could also just use [IDBKey, []] as the upper bound.

More input on the use cases here is definitely needed.
 
Parent-child relationship can be constrained by using hierarchical key, in which child primary key is [parentKey, uniqueChildId]. In this way, an parent record can query its child objects by IDBKeyRange.starts([parentKey]).  

Prefixing compound (array) index is useful for equal AND query. For example, to find all records of 'index1' = 'A' and 'index2' = 'B', we can open two cursors, index1 with IDBKeyRange.starts(['A']) and index2 with IDBKeyRange.starts(['B']).  

BTW, what are the use for number and date?

That fell out of the [k].... [successor(k)] approach for arrays, e.g [1] ... [1+epsilon] permits any array starting with 1.


I prefer the function name to be, IDBKeyRange.startsWith or simply IDBKeyRange.starts. 
    
My implementation is simply:

ydn.db.KeyRange.starts = function(value) {
  var value_upper;
  if (goog.isArray(value)) {
    value_upper = goog.array.clone(value);
    // Note on ordering: array > string > data > number
    value_upper.push('\uffff');
  } else if (goog.isString(value)) {
    value_upper = value + '\uffff';
  } else {
    return ydn.db.KeyRange.only(value);
  }

  return ydn.db.KeyRange.bound(value, value_upper, false, true);
};

Which work fine. But platform implementation is better to cover conner cases, as you said.


Platform implementation would also handle future key types; we're considering "binary key" support (e.g. Uint8Arrays) which could sort between string and array.

 


On Tuesday, October 8, 2013 7:41:49 AM UTC+8, Joshua Bell wrote:
When discussing incremental additions to the Indexed DB API with some other browser vendors, the need for an API that would yield an IDBKeyRange for a given prefix was brought up.

e.g. if you're using an object store to represent a file system, you might have keys of the form:

"/tmp/a
"/tmp/dir/b"
"/tmp/dir/c"
"/tmp/dir2/d"
"/tmp/e"

If you want to iterate over everything in "/tmp/dir" you need to construct a key range for everything with prefix "/tmp/dir/". Constructing such a key range requires somewhat intricate knowledge of JS strings and IDB keys. We talked about adding an API such as:

IDBKeyRange.forPrefix(key)

This is something that can be "prollyfilled" today, so to get feedback before we add it to the platform I spun up a basic implementation:


Although strings keys are the obvious case, I tackled numbers and dates and arrays as well. Arrays raised some interesting edge cases, so I'd appreciate feedback. Is this useful? Does it meet your expectations? Do you have use cases beyond string keys? Is this something where a platform addition makes sense, or is the use case too limited?

--
You received this message because you are subscribed to the Google Groups "Chromium HTML5" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-html...@chromium.org.
To post to this group, send email to chromiu...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-html5/.
For more options, visit https://groups.google.com/a/chromium.org/groups/opt_out.

Reply all
Reply to author
Forward
0 new messages