RE: [IndexedDB] Multientry and duplicate elements

The approach you described makes sense to us.
Thanks for clarifying.

Israel

On Saturday, March 03, 2012 5:07 PM, Jonas Sicking wrote:
> On Fri, Mar 2, 2012 at 8:49 PM, Israel Hilerio <israelh@microsoft.com> wrote:
> > We would like some clarification on this scenario.  When you say that
> > FF will result on 1 index entry for each index that implies that the
> > duplicates are automatically removed.  That implies that the
> > multiEntry flag doesn't take unique into consideration.  Is this correct?
> 
> Not quite.
> 
> In Firefox multiEntry indexes still honor the 'unique' constraint.
> However whenever a multiEntry index adds an Array of entries to an index, it
> first removes any duplicate values from the Array. Only after that do we start
> inserting entries into the index. But if such an insertion does cause a 'unique'
> constraint violation then we still abort with a ConstraintError.
> 
> Let me show some examples:
> 
> store = db.createObjectStore("store");
> index = store.createIndex("index", "a", { multiEntry: true } ); store.add({ x: 10 },
> 1); // Operation succeeds, store contains one entry store.add({ a: 10 }, 2); //
> Operation succeeds, store contains two entries // index contains one entry: 10
> -> 2 store.add({ a: [10, 20, 20] }, 3); // Operation succeeds, store contains three
> entries // index contains three entries: 10->2, 10->3, 20->3 store.add({ a: [30,
> 30, 30] }, 4); // Operation succeeds, store contains four entries // index
> contains four entries: 10->2, 10->3, 20->3, 30->4 store.put({ a: [20, 20] }, 3); //
> Operation succeeds, store contains four entries // index contains three entries:
> 10->2, 20->3, 30->4
> 
> 
> Similar things happen for unique entries (assume that the transaction has a
> errorhandler which calls preventDefault() on all error events so that the
> transaction doesn't get aborted by the failed inserts)
> 
> store = db.createObjectStore("store");
> index = store.createIndex("index", "a", { multiEntry: true, unique: true } );
> store.add({ x: 10 }, 1); // Operation succeeds, store contains one entry
> store.add({ a: 10 }, 2); // Operation succeeds, store contains two entries //
> index contains one entry: 10 -> 2 store.add({ a: [10] }, 3); // Operation fails due
> to the 10 key already existing in the index store.add({ a: [20, 20, 30] }, 4); //
> Operation succeeds, store contains three entries // index contains three
> entries: 10->2, 20->4, 30->4 store.add({ a: [20, 40, 40] }, 5); // Operation fails
> due to the 20 key already existing in the index store.add({ a: [40, 40] }, 6); //
> Operation succeeds, store contains four entries // index contains four entries:
> 10->2, 20->4, 30->4, 40->6 store.put({ a: [10] }, 4); // Operation fails due to the
> 10 key already existing in the index // store still contains four entries // index
> still contains four entries: 10->2, 20->4, 30->4, 40->6 store.put({ a: [10, 50] }, 2);
> // Operation succeeds, store contains five entries // index contains six entries:
> 10->2, 20->4, 30->4, 40->6, 50->2
> 
> 
> To put it in spec terms:
> One way to fix this would be to add the following to "Object Store Storage
> Operation" step 7.4:
> "Also remove any duplicate elements from /index key/ such that only one
> instance of the duplicate value exists in /index key/".
> 
> Maybe also add a note which says:
> "For example, the following value of /index key/ [10, 20, null, 30, 20] is
> converted to [10, 20, 30]"
> 
> 
> For what it's worth, we haven't implemented this in Firefox by preprocessing
> the array to remove duplicate entries. Instead we for non-unique indexes keep
> a btree key'ed on indexKey + primaryKey. When inserting into this btree we
> simply ignore any collisions since they must be due to multiple identical entries
> in a multiEntry array.
> 
> For unique indexies we keep a btree key'ed on indexKey. If we hit a collision
> when doing an insertion, and we're inserting into a multiEntry index, we do a
> lookup to see what primaryKey the indexKey maps to. If it maps to the
> primaryKey we're currently inserting for, we know that it was due to a
> duplicate entry in the array and we just move on with no error. If it maps to
> another primaryKey we roll back the operation and fire a ConstraintError.
> 
> Let me know if there's still any scenarios that are unclear.
> 
> / Jonas

Received on Monday, 5 March 2012 20:10:38 UTC