如何显示每个发件人的最新电子邮件(从每个组中排名前1行)?

时间:2017-09-24 16:43:52

标签: indexeddb

我想使用indexedDB管理典型电子邮件收件箱中的电子邮件列表。每封电子邮件只有三个属性:

  1. Time - 已收到时间电子邮件
  2. Sender - 发件人的电子邮件地址
  3. Subject - 电子邮件的标题
  4. 我应该如何在indexedDB中建模数据?如何制定查询以实现以下目标:

    1. 列出每个Sender(时间,发件人,主题)的最新电子邮件,按每封最新电子邮件的Time(降序排序)排序。此列表显示来自每个Sender的最新电子邮件。
    2. 根据Sender,列出Sender排序的Time所有电子邮件。
    3. 我对NoSql完全不熟悉。我想我可以通过为Sender创建索引然后打开索引的游标来相对容易地实现第二个查询。

      对于第一个查询,我考虑维护一个单独的商店Latest,该商店会保留每个发件人的最新电子邮件。每次收到新电子邮件时,都必须Put进入Latest。显然,这充满了问题,我需要帮助以“正确”的方式去做。

2 个答案:

答案 0 :(得分:1)

使用IndexedDB包装器JsStore,您可以创建一个表,用于存储带有自动增量列的邮件(例如Id),并使用此列(Id)对数据进行排序。

盯着案例#2:

用于检索发件人的所有电子邮件

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);
    }
});

案例#1:

如果我们可以在JsStore中使用GROUP BY子句,那么很容易为每个发件人检索最新的电子邮件但不幸的是,当前版本的JsStore没有提供它,但它的next release可能会支持它。

直到那时我们可以在完整记录中过滤邮件,或者可以使用发件人的电子邮件ID逐个获取。

过滤完整记录

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);
    }
});

逐个获取每个发件人的最新邮件并推送到一个数组中:

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);
        }
    })
});

您可以查看其SQL类型语法,以便在official site上使用IndexedDB进行查询。您可以轻松地解释上述代码。

答案 1 :(得分:0)

作为猜测,它将涉及使用基于多个属性的索引。这有点违反直觉,一开始很难做到,但基本上是:

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.

  }
}

最糟糕的情况是你加载所有项目,然后在内存中进行所有过滤和排序。与最坏的情况相比,上面的代码减少了反序列化的对象数量(从indexedDB加载到js land),并且这些项已经被排序,而nextUnique逻辑发生在C ++ land而不是Js land,所以它的评估速度要快得多。 / p>

对于案例#2,您使用range参数进行openCursor的技巧。如果您想要从最旧到最新的时间排序,则不再需要传递prev。

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);
}

基本上,发件人时间索引有点像SELECT * ORDER BY sender ASC, time ASC中间结果,然后您可以扫描。因此,在第一种情况下,您使用nextUnique只需跳转到下一个新发件人并获取他们的第一个项目,然后再次跳过。在第二种情况下,您使用像SELECT * FROM table WHERE sender >= sender && sender <= sender && time >= min-time && time <= max-time这样的where子句进行限制。但请注意,这是一个严重的简化。实际上,我们正在利用这样一个事实:我们绕过了indexedDB中的伪where子句的短路评估,如果我们有更宽松的发送条件,这将导致一切搞砸。但在这种情况下,发送者要么没有条件(在我们只使用排序顺序的情况下),或者在情况2中,发送者总是相同的发送者,我们知道布尔子句的第一部分总是为真所以第二个子句总是评价。