Bug 21836 - Remove NotSupportedError on creating index for multiEntry index with array keyPath
Remove NotSupportedError on creating index for multiEntry index with array ke...
Status: RESOLVED LATER
Product: WebAppsWG
Classification: Unclassified
Component: Indexed Database API
unspecified
PC All
: P2 normal
: ---
Assigned To: This bug has no owner yet - up for the taking
public-webapps-bugzilla
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2013-04-26 00:53 UTC by Kyaw Tun
Modified: 2013-04-30 02:07 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kyaw Tun 2013-04-26 00:53:18 UTC
In creating index, the specification state that:

"If keyPath is and Array and the multiEntry
property in the optionalParameters is true, then a DOMException of type
NotSupportedError must be thrown."

However it is unnecessary. multiEntry is no different than
non-multiEntry index value, except the reference value is repeated. This
specification limit generalizes usage of composite index for key joining
algorithm.

Composite index with multiEntry is very useful, like modelling graph data
and many-to-many relationship. Currently query on such model are limited to
single index. It is also very unlikely that web developer will use excessive indexing.

Discussion on: http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0379.html
Comment 1 Joshua Bell 2013-04-26 16:47:55 UTC
Thanks. Adding this to the "possible for V2" list by marking Resolved/Later.
Comment 2 Jonas Sicking 2013-04-29 11:17:31 UTC
There are several ways that you could interpret an array keyPath on a multiEntry index.

Consider a multiEntry index with keyPath ["a", "b"]

It's pretty intuitive that storing a value like:

{
  id: 1,
  a: "apple",
  b: "orange"
}

would add the following entries to the index:

"apple" -> 1
"orange" -> 1


But what would storing the following value result in?

{
  id: 1,
  a: ["apple", "x"],
  b: ["orange", "y"]
}

Would this result in the following entries

A)
["apple", "x"] -> 1
["orange", "y"] -> 1

or

B)
"apple" -> 1
"x" -> 1
"orange" -> 1
"y" -> 1

or

C)
["apple", "orange"] -> 1
["x", "y"] -> 1


Normally when an Array is used as a KeyPath the resulting key consists of an Array where each entry in the Array is the result of evaluating that KeyPath. So in this example the result would be

[["apple", "x"], ["orange", "y"]]

Applying normal multiEntry processing to that key would mean that behavior A) above is the correct answer.


However a common use-case for multiEntry+Array-KeyPath is likely things like creating a "name" index which indexes on both first names and last names. In that case you'd likely want the union of all values from each element in the Array. I.e. you'd want behavior B) above.


Another way to look at it is that just like adding multiEntry to an index on "a" lets you store an Array in the "a" property to add one entry for each value in that array, so could adding multiEntry to an index on ["a", "b"] let you store Arrays in the "a" and "b" properties to add one entry for each value in those two arrays. This interpretation says that C) above is the correct behavior.


So I'm somewhat inclined to solve the use cases here using bug 10000. Or to use some other flag here than "multiEntry" which more clearly indicates which of the behaviors above should be used.
Comment 3 Kyaw Tun 2013-04-29 13:48:07 UTC
Thank Jonas, for very clear explanation. Both use case B) and C) must be able to specify.

Previously, I was not understand the specification correctly. I was talking from developer point of view. In fact, array keyPath with multiEntry does not make sense and the specification is correct. What I refer turn out to be composite index (array keyPath) of multiEntry index. Composite index, itself, is not multiEntry.   

Bug 10000 sounds nice, but its implication is ugly.

Indexing specification is the most beautiful part of IndexedDB API. It could go father, following google database store interpretation.


Could we specify such that

1. multiEntry effect writing index. 
2. element of array keyPath is evaluated as index value first and then keyPath of record value (current specification). If element of array keyPath is the name of index, its value is respective index value. If the name of index does not exist, it is evaluated as usual. 

In this way both use case B) and C) can be specified intuitively.
Comment 4 Jonas Sicking 2013-04-29 18:32:09 UTC
Sorry, I don't really understand what you are proposing. Could you provide some example code?
Comment 5 Kyaw Tun 2013-04-30 02:07:41 UTC
Suppose we have a record value of:

var human = {
  taxon: 9606,
  classification: ['Animalia', 'Mammalia', 'Primates'],
  name: {
    genus: 'Homo',
    species: 'sapiens'
  },
  habitat: ['asia', 'americas', 'africa', 'europe', 'oceania'] 
}


store = db.createObjectStore('specie', {keyPath: 'taxon'});
store.createIndex('clade', 'classification', {multiEntry: true});
store.createIndex('habitat', 'habitat', {multiEntry: true});
store.createIndex('binomen', ['name.genus', 'name.species']);

The following composite index is used to list specie table. This is use case A.

store.createIndex('specie', ['classification', '.binomen'], {unique: true});

It should create a index value of

[['Animalia', 'Mammalia', 'Primates'], ['Homo', 'sapiens']]

The following composite index is used to query specific clad order by name. This is use case B.

store.createIndex('clad-name', ['.clade', '.binomen']);

It should crate index values of

['Animalia', ['Homo', 'sapiens']]
['Mammalia', ['Homo', 'sapiens']] 
['Primates', ['Homo', 'sapiens']] 

The following composite index is used to query habitant and clad.

store.createIndex('clad-habitat', ['.clade', '.habitat', '.binomen');

It should crate index values of

['Animalia', 'africa', ['Homo', 'sapiens']]
['Animalia', 'asia', ['Homo', 'sapiens']]
['Animalia', 'americas', ['Homo', 'sapiens']]
['Animalia', 'europe', ['Homo', 'sapiens']]
['Animalia', 'oceania', ['Homo', 'sapiens']]
['Mammalia', 'africa', ['Homo', 'sapiens']]
['Mammalia', 'asia', ['Homo', 'sapiens']]
['Mammalia', 'americas', ['Homo', 'sapiens']]
['Mammalia', 'europe', ['Homo', 'sapiens']]
['Mammalia', 'oceania', ['Homo', 'sapiens']]
['Mammalia', 'africa', ['Homo', 'sapiens']] 
['Primates', 'africa', ['Homo', 'sapiens']]
['Primates', 'asia', ['Homo', 'sapiens']]
['Primates', 'americas', ['Homo', 'sapiens']]
['Primates', 'europe', ['Homo', 'sapiens']]
['Primates', 'oceania', ['Homo', 'sapiens']]


Notice that the last two composite index is created using array keyPath consisting of keyPath or index, in which it is argumented by a dot. 

Sorry, previously I was referring only use case for A and B. Use case C is interesting, but will not be common need.