Vermutlich würde man Indizes verwenden, die auf mehreren Eigenschaften basieren. Es ist ein wenig kontraintuitiv und hart rechts auf dem ersten zu bekommen, aber im Wesentlichen:
function onupgradeneeded(event) {
// ...
// make sure to use explcit and exact property names in second
// param to createIndex
store.createIndex('sender-time', ['sender', 'time']);
}
function get_latest() {
// ...
var index = store.index('sender-time');
// use prev so that the sort order is descending instead of
// ascending
// first arg is the range, we are not limiting items in any way
// here, at least explictly. implicitly we are filtering out items
// without a sender or without a time since missing values cause
// the object to be excluded from the index.
var request = index.openCursor(null, 'prevunique');
request.onsuccess = function() {
// This iterates over all items. The trick then is to advance the
// cursor to the prev unique item. Since items in the index are
// ordered first by sender, then by time, jumping to prev unique
// sender skips over the other records for the same sender you
// would see if you normally just advanced the cursor.
}
}
Das Worst-Case-Szenario ist, dass Sie alle Elemente laden, dann alles tun, die Filterung und Sortierung im Speicher. Im Vergleich zum schlimmsten Fall reduziert der obige Code die Anzahl der deserialisierten Objekte (geladen von indexedDB in js land), und die Elemente sind bereits sortiert, und die nächsteEindeutige Logik passiert in C++ Land anstelle von Js Land, so dass sie viel schneller auswertet.
Für Fall # 2, Sie tun einen Trick mit dem Bereich Parameter zu openCursor. Sie müssen nicht mehr vorheilen, wenn Sie die Zeit vom ältesten zum neuesten sortieren möchten.
function get_sender() {
var index = store.index('sender-time');
var lowerBound = ['sender-value-here', smallest date possible in js];
var upperBound = ['the-same-sender-value-here', largest date possible in js];
var range = IDBKeyRange.bounds(lowerBound, upperBound);
// NOTE: above might be wrong I forget, you have to make the
// bounds inclusive, so that sender matches and the bounds do not
// result in excluding all records
// again here you don't need 'prev' 2nd param unless you want
// reverse order
var request = index.openCursor(range);
}
Im Wesentlichen ist ein Sender-Zeitindex der Art wie ein SELECT * ORDER BY sender ASC, time ASC
Zwischenergebnis, das Sie dann scannen. Im ersten Fall verwenden Sie also nextUnique, um einfach zum nächsten neuen Absender zu springen und das erste Element zu erhalten und dann erneut zu überspringen. Im zweiten Fall beschränken Sie mit einer Where-Klausel wie SELECT * FROM table WHERE sender >= sender && sender <= sender && time >= min-time && time <= max-time
. Aber beachten Sie, dass dies eine starke Vereinfachung ist. In Wirklichkeit nutzen wir die Tatsache aus, dass wir die Kurzschlussevaluierung der Pseudo-Where-Klausel, die in indexedDB läuft, umgehen, was dazu führen würde, dass alles versaut wird, wenn wir eine lose Absenderbedingung haben. Aber in diesem Fall ist der Absender entweder nicht konditioniert (Abschnitt 1, wo wir nur die Sortierreihenfolge verwenden), oder im Fall 2 ist der Absender immer derselbe Absender und wir wissen, dass der erste Teil der Booleschen Klausel immer wahr ist, also immer die zweite bewertet.
Danke für die Vorschläge. Würden Sie in Betracht ziehen, einen separaten Laden "Latest" zu führen, wie ich in meiner Frage eine praktikable Option beschrieben habe? –
Nicht, es sei denn, dies ist die einzige Möglichkeit. Mit nosql dbs verfolgen Sie und bevorzugen Leistung gegenüber normaler Form. – Josh
Hinweis, das nächste oder vorherige eindeutige Datum funktioniert möglicherweise nicht, da Sender und Uhrzeit Teil des Schlüsselpfads sind. Vielleicht versuchen Sie es mit Fortschritt oder nur mit dem Absender, wenn das möglich ist. – Josh