IndexedDB - 计算值的出现次数?

时间:2014-06-25 19:08:42

标签: javascript google-chrome-extension indexeddb

我正在为日语在线词典的Chrome扩展程序工作,我试图记录并显示用户的查询统计信息,因此他知道他最缺少的日语术语。

为此,我的目的是在过去的X天内显示查询次数最多的汉字(日文字符)。所以我在我的扩展indexedDB中创建了一个简单的对象存储库,其中包含汉字/日期对和autonumered密钥,但似乎没有一种方法可以在indexedDB中进行这些查询?

是唯一可以按日期过滤并使用游标计算出现次数并使用javascript回调进行计算的方法吗?

编辑:用于创建数据库的代码

const DB_NAME = "kioku"
const DB_VERSION = 1;
const KANJI_STORE = "kanji";

var db;
(function() {
    var request = window.indexedDB.open(DB_NAME, DB_VERSION);
    request.onupgradeneeded = function(e) {
        db = e.target.result;
        var kanjiStore = db.createObjectStore(KANJI_STORE, { autoIncrement: true });
        kanjiStore.createIndex("date", "date", { unique: false });
    }
})();

通过事件处理程序添加数据

function newRecentKanjiHandler(request, sender, sendResponse) {
    /* ...stuff before this point was irrelevant so I removed it */

    var kanjiStore = db.transaction([KANJI_STORE], "readwrite").objectStore(KANJI_STORE);
    kanjiStore.add({kanji: request.kanji, date: Date.now()});
}

包含示例数据的屏幕截图

Screenshot with sample data

在这种情况下,我想显示类似

的内容
x3: 杉
x2: 刀, 尻
x1: 刃

对于用户。在我按日期范围过滤后,只是简单地计算出现的情况,在本例中我没有,因为时间戳在一小时内,我的目的是过滤最后几天或几周。

1 个答案:

答案 0 :(得分:1)

我喜欢这个问题。我很肯定有人会比我有更好的答案,但这里有一个随机的答案。

首先,我应该指出一个问题,即尝试将event.target.result分配给db时会遇到问题。您试图将仅在其范围内有效的对象推送到外部范围。这只会在以后引起你的问题。我建议在JavaScript中学习更多有关异步函数的知识。

其次,我首先从当前的方向退一步,回顾一下你试图解决的问题的一些基本假设。有时indexedDB不是最好的解决方案。不幸的是,使用indexedDB会迫使您尽快面对这些设计问题。

您是否需要存储每个关键事件?如果不是,则问题的规模限于不同的汉字键的数量而不是事件的数量。您可以完全放弃使用indexedDB并使用一个简单的对象来保存到本地存储。

如果比例有点大,那么确定您是仅仅出于问题的目的存储事件,还是出于其他目的?如果这只是您自己问题的目的,那么请考虑更改您存储的内容(架构)以仅解决其特定目的,而不是其他目的的未知列表。

例如,如果它只是为了这个目的,并且它不必扩展,您可以完全避免indexedDB而只是本地存储。如下所示:

function onCharEvent(char) {
  var obj = JSON.parse(localStorage.KANJI_STATS || '');
  var bar = obj[char] || {char: char, count: 0};
  bar.count++;
  bar.lastObserved = Date.now();
  obj[char] = bar;
  localStorage.KANJI_STATS = JSON.stringify(obj);
}

如果该功能仅用于此目的,并且必须是大规模的,则可以简化架构。首先想象一下,在完成所有分组,排序和计数之后,查询的列表式结果应该是什么样子。然后考虑如何在此模式中执行添加和放置操作。如果我理解正确,您希望获得如下所示的结果集合:

Kanji char | Count | Last observed
----------------------------------
char1      | 1     | 1234123412345
char2      | 2     | 4643563456345
char3      | 3     | 3245234523452

每个实例(记录)都包含一个唯一的字符。计数表示观察角色的次数。最后观察到的属性表示角色最近观察的时间。

// Setup or change the schema
function onUpgradeNeeded() {
  var db = this.result;
  var store = db.createObjectStore('kanji', {keyPath: kanjiChar});
  store.createIndex('lastObserved','lastObserved');
}

function openDB(onOpen) {
  var openRequest = indexedDB.open(DBNAME,DBVERSION);
  openRequest.onupgradeneeded = onUpgradeNeeded;
  openrequest.onsuccess = function() {
    onOpen(this.result);
  };
}

function onKeyEvent(event) {
  var kanjiChar = event.target.value;
  openDB(function(db) {
    put(db, kanjiChar);
  });
}

// Insert or update the kanji in the store
function put(db, kanjiChar, oncomplete) {
  var tx = db.transaction('kanji','readwrite');
  tx.oncomplete = function() {
    oncomplete(kanjiChar);
  };

  var store = tx.objectStore('kanji');      
  store.openCursor(kanji).onsuccess = function() {
    var cursor = this.result;
    if(cursor) {
      var obj = cursor.value;
      obj.count = obj.count ? obj.count + 1 : 1;
      obj.lastObserved = Date.now();
      cursor.update(obj);
    } else {
      store.add({
        kanjiChar: kanji,
        count: 1,
        lastObserved: Date.now()
      });
    }
  };
}

function getStats(db, oncomplete) {
  var tx = db.transaction('kanji');
  var allStats = [];

  tx.oncomplete = function() {
    oncomplete(allStats);
  };

  var kanjiStore = tx.objectStore('kanji');
  var lastObservedIndex = kanjiStore.index('lastObserved');
  var LIMIT = 10;
  var counter = 0;
  lastObservedIndex.openCursor('prev').onsuccess = function() {
    var cursor = this.result;
    if(cursor) {
      allStats.push(cursor.value);
      if(counter++ < LIMIT) {
        // Only continue 
        cursor.continue();
      }
    }
  };
}