When updating an object store record, obsolete index entries are not deleted immediately - they are only deleted when a cursor from a read/write transaction happens to iterate past them.
This optimizes for write performance but impacts read performance.
The mechanism by which this works is also poorly documented in the code. It is documented in the coding scheme https://chromium.googlesource.com/chromium/src/+/da3f614dc0e3d04f62227cddb136997731dcd443/content/browser/indexed_db/leveldb_coding_scheme.md
"The version field is used to weed out stale index data. Whenever new object store data is inserted, it gets a new version number, and new index data is written with this number. When the index is used for look-ups, entries are validated against the “exists” entries, and records with old version numbers are deleted when they are encountered in GetPrimaryKeyViaIndex, IndexCursorImpl::LoadCurrentRow and IndexKeyCursorImpl::LoadCurrentRow."
Comment 1 by jsb...@chromium.org
, Mar 22 2017