2017-09-24 2 views
0

Ich möchte die Liste der E-Mails in einem typischen E-Mail-Posteingang mit indexedDB verwalten. Jede E-Mail hat nur drei Eigenschaften:Wie zeige ich die letzte E-Mail von jedem Absender an (bekomme oberste 1 Zeile von jeder Gruppe)?

  1. Time - Zeit E-Mail
  2. Sender empfangen wurde - E-Mail-Adresse des Absenders
  3. Subject - der Titel der E-Mail

Wie soll ich das Datenmodell in indexedDB und wie sollte ich die Abfragen formulieren, um Folgendes zu erreichen:

  1. Listen Sie die letzte E-Mail von jedem Sender (Zeit, Absender, Betreff), geordnet nach der Time (absteigende Reihenfolge) der letzten E-Mail. Diese Liste zeigt jeweils eine E-Mail von jedem Sender.
  2. Gegeben eine Sender, liste alle E-Mails von dieser Sender, bestellt von Time.

Ich bin völlig neu in NoSql. Ich denke, dass ich die zweite Abfrage relativ leicht erreichen kann, indem ich einen Index für erstelle und dann einen Cursor für den Index öffne.

Für die erste Abfrage dachte ich an die Pflege eines separaten Geschäfts, Latest, die die neuesten E-Mails von jedem Absender hält. Jedes Mal, wenn eine neue E-Mail empfangen wird, muss sie Put in Latest sein. Offensichtlich ist dies mit Problemen behaftet und ich brauche Hilfe auf dem "richtigen" Weg, dies zu tun.

Antwort

0

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.

+0

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? –

+0

Nicht, es sei denn, dies ist die einzige Möglichkeit. Mit nosql dbs verfolgen Sie und bevorzugen Leistung gegenüber normaler Form. – Josh

+0

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

1

Mithilfe eines IndexedDB-Wrappers JsStore können Sie eine Tabelle zum Speichern von E-Mails mit einer Autoinkrement-Spalte (z. B. Id) erstellen und diese Spalte (Id) zum Sortieren der Daten verwenden.

mit dem Fall # Staring 2:

Für alle E-Mails von einem Absender Abrufen

var Connection = new JsStore.Instance("Database_name"); 
Connection.select({ 
    From: "Inbox", // Inbox is your table name 
    Where:{ 
     Sender: sender_email 
    }, 
    Order: { 
     By: "Id", 
     Type: "desc" 
    }, 
    OnSuccess:function (results){ 
     console.log(results); 
    }, 
    OnError:function (error) { 
     console.log(error); 
    } 
}); 

Fall # 1:

Es wäre sehr einfach, die abgerufen werden letzte E-Mail für jeden Absender, wenn wir die GROUP BY-Klausel in JsStore verwenden könnten, aber leider nicht in der aktuellen Version von JsStore, aber wahrscheinlich wird sie mit unterstützt sein next release.

Bis dahin können wir die E-Mails auf den vollständigen Datensatz filtern oder können eins nach dem anderen mit der E-Mail-ID des Absenders abrufen.

Filtering auf vollständige Aufzeichnung:

var Connection = new JsStore.Instance("Database_name"); 
Connection.select({ 
    From: "Inbox", // Inbox is the table name 
    Order: { 
     By: 'Id', 
     Type: "desc" 
    }, 
    OnSuccess:function (results){ 
    var sendersName = []; 
    var filteredMails = results.filter(function(mail){ 
     if(sendersName.indexOf(mail.sender) == -1){ 
      sendersName.push(mail.sender); 
      return mail; 
     } 
    }); 
    console.log(filteredMails); 
    }, 
    OnError:function (error) { 
     console.log(error); 
    } 
}); 

für jeden Absender Fetch neuesten Mail eins nach dem anderen, und drücken Sie in ein Array:

var mails=[]; 
senders_email.forEach(function(value){ // keep the list of senders email in the array "sender_email" 
    Connection.select({ 
     From:'Inbox', 
     Where:{ 
      Sender:value 
     }, 
     Limit:1, 
     Order: { 
      By: 'Id', 
      Type: "desc" 
     }, 
     OnSuccess:function(result){ 
      result.length > 0 && mails.push(result[0]); 
     }, 
     OnError:function(err){ 
      console.log(err); 
     } 
    }) 
}); 

Sie einen Blick auf seine SQL haben Geben Sie die Syntax für die Abfrage mit IndexedDB unter official site ein. Es ist dann leicht für Sie, die obigen Codes zu interpretieren.

Verwandte Themen