Re: [IndexedDB] KeyPaths and missing properties.

On Wed, May 19, 2010 at 9:38 PM, Jonas Sicking <jonas@sicking.cc> wrote:

> On Wed, May 19, 2010 at 2:36 AM, Jeremy Orlow <jorlow@chromium.org> wrote:
> > Interesting you'd bring this up.  Andrei and I were just looking at
> indexes
> > as specced and wondered whether it still makes sense to allow indexes to
> not
> > have a keyPath.
>
> I think so. Consider for example a objectStore that contains entries like:
>
> { name: "Elvis Presley", born: "1935-1-8", death: "1977-8-16" }
>
> But index on how old the person was when he/she died. I guess you
> could require that people store a property containing the age, however
> it seems unfortunate to require modifying the stored data.
>
> Worse, you might have entries like:
>
> { id: 5, givenName: "Benny", otherNames: ["Göran", "Bror"],
> familyName: "Andersson", age: 63, interest: "Music" }
>
> in order to search for people, you might want to search for a name, no
> matter if that is a given name, a family name, or second name.
> Currently you can accomplish this by inserting 4 entries into an
> index, all pointing to the same entry in the objectStore. I can't
> think of a sane way to accomplish this using only keyPath.
>

I think the main use case here is the need to allow an unknown quantity of
entries in the index to one entry in the objectStore.  What if we allowed
keyEntry's to be any javascript expression and allow them to return arrays
of indexible data.  In this case, the expression would return an array of
otherNames + the givenName + the familyName.  The keyPath already is
essentially just a javascript expression, so this doesn't seem like too big
of a leap.

This would also support your age upon death use case.  (Though I think
requiring the developer to store that age if they want it indexed isn't too
bad of an answer either.)

Thoughts?


> >  And, if so, whether we should tie insertion into the
> > objectStore to insertion to the index. The main reason to make such
> changes
> > would be to enforce a notion of database consistency.
>
> You mean so that you would have to pass in index keys to the
> insert/modify functions? In other words, require at an API level that
> indexes were always up to date?
>
> This is an interesting idea. I can't really say I feel strongly one
> way or another. I guess it depends on what the API would look like.
> The nice thing about what we have now is that the API is pretty
> simple.
>

One possible way to implement it: add/modify/addOrModify could have an
optional parameter that takes an associative array.  For example, {age: 63,
interest: "music"} if you were indexing on age and interest.

That said, I think I like my above proposal better.


> > So I guess the
> > fundamental question here is whether there should be a 1:1 mapping
> between
> > entries in an objectStore's indexes and the objectStore itself.
>
> I'm not sure what you mean by "a 1:1 mapping"? Do you mean that there
> are the same number of entries in the index as there are in the
> objectStore?
>

Yes.  But I think your indexing on multiple names use case may have already
sold me on supporting something other than just 1:1 mappings.


>  > On Wed, May 19, 2010 at 3:06 AM, Jonas Sicking <jonas@sicking.cc>
> wrote:
> >>
> >> Hi IndexedDB fans!
> >>
> >> So another issue that's come up here. This question is orthogonal to
> >> the other discussed issues and applies equally to both the existing
> >> API, and the mozilla proposed API, so I figured it was safe to raise
> >> right away.
> >>
> >> What should happen if you insert a object into an objectStore which
> >> has an index attached to it, but the property defined by the keyPath
> >> in the index does not exist? Consider a database with an objectStore
> >> called "people" with keyPath "name". The objectStore has an
> >> auto-populated index named "phone numbers" with keyPath "phone". The
> >> objectStore is initially empty.
> >>
> >> What should happen if you attempt to store an object with value {
> >> name: "Benny", email: "benny@sweden.com" } ?
> >>
> >> There are three possible behaviors I can think of:
> >>
> >> 1. The storing operation should fail and an error event should be fired.
> >> 2. The storing operation should succeed, but no records should be
> >> added to the "phone" index.
> >> 3. The storing operation should succeed and a record should be added
> >> to the "phone" index using null as key.
> >>
> >> Which one is correct behavior? What if the "phone numbers" index is
> >> flagged as unique?
> >>
> >> I definitely think there is a use case for allowing records to be
> >> stored even if there are indexes on missing properties. Consider for
> >> example a objectStore containing people where not everyone has a known
> >> phone number. It still seems useful to be able to search based on
> >> phone number in this objectStore. To satisfy this use case either
> >> solution 2 or 3 would work. 3 would additionally allow searching for
> >> everyone without a phone number, though I'm not sure how important
> >> that is. On the other hand 2 would be more space effective in that
> >> only relevant records would be stored.
> >>
> >> Possibly we'll want to add a 'required' flag to the createIndex
> >> function specifying if the index should cause behavior 1 or behavior
> >> 2. So far I'm not a big fan of 3, but I'm all ears for input.
> >
> > If we went with (1) then it seems as though developers could simply
> insert
> > items with .phone=null to get around the limitation.
>
> People doing that doesn't seem to really change anything. The question
> would just turn into "what should we do if the key is absent, null or
> undefined". The same 1, 2, 3 answers still seem like possible answers.
>
> > 3 seems like it'd be error prone and somewhat confusing.
> > If we decide there should be a 1:1 mapping then it seems we're choosing
> > between 1 and 3.  And if not, then I think 2 is the clear answer.
>
> I'm still not sure what the "a 1:1 mapping" means, so not really
> following your logic here.
>

Does it make sense now?  Either way, I guess I'm leaning towards 2 at this
point since there do seem to be valid use cases for multiple (or 0) entries
in one index pointing to one objectStore entry.


> >> There is a similar issue if an objectStore uses in-line keys. Consider
> >> a database with a objectStore called "people" with keyPath "name" and
> >> no key generator. What if someone inserts an object with the value {
> >> email: "benny@sweden.com" }? I would think that this should be an
> >> error, but it doesn't appear that any of the steps in "Object Store
> >> Storage steps" says to create an error.
> >
> > This is probably just an omission in the spec.  If so, someone should
> file
> > an issue on it.
>
> Agreed. I'll file a bug.
>
> >> Finally, there is the issue of what should happen if someone tries to
> >> insert a number as a value into an objectStore with a keyPath and a
> >> key generator. Consider the objectStore "albums" with keyPath "id" and
> >> a key generator enabled. What should happen if someone tries to insert
> >> the value 9 into this table? If an object was inserted, then this
> >> would result in that objects 'id' property being set to the next
> >> generated value from the generator, however it doesn't really make
> >> sense to set a property on a number. Same question obviously applies
> >> if the stored value is a boolean, a string, or any other primitive JS
> >> type, or types such as regexps and File objects. I think that in all
> >> these cases the operation should fail.
> >
> > Agreed.
>
> I'll file a bug.
>
> >> The question also applies if the stored value is an array. Technically
> >> Javascript allows setting values on arrays, however the structured
> >> clone algorithm drops these values, and so it seems to add needless
> >> complexity for the implementation if the only time you need to
> >> serialize/deserialize arrays with non-integer properties is in this
> >> one case. Additionally, the id would be lost when the value is read as
> >> that is done using the structured clone algorithm too.
> >
> > Hm.  I'm having trouble following this case.  Any chance you could
> explain
> > it further?
>
> Consider the following. An objectStore with keyPath "id" and a key
> generator enabled, and the last generated key had the value 6. If I
> call
>
> objectStore.put({ name: "Benny" });
>
> then that would store an object like
>
> { name: "Benny", id: 7 }
>
> in the objectStore. The question is, what should happen if I instead had
> called:
>
> myObjectStore.put(["Benny"]);
>
> The spec now says to create a structured clone of the value (i.e. the
> array), and then set its .id property. This is perfectly valid in
> javascript. I.e. JS allows you to do:
>
> a = ["Benny"];
> a.id = 7;
>
> This results in an array object of length 1, but which has a .id
> property set to 7. It would be possible to store such an object in the
> database and have it accessible if you do
>
> myObjectStore.get(7);
>
> However since the structured clone algorithm is used when reading the
> value from the database, you'd still just get back a normal array with
> no .id property.
>
> In general the whole situation seem complex and surprising, and so I
> don't think we should allow it.
>

Oh, interesting!  Do you know why the structured clone algorithm is specced
that way?

Anyway, I'd agree that disallowing it is probably the right answer.

J

Received on Wednesday, 19 May 2010 23:59:31 UTC