javascript - IndexedDB - 计算值出现次数?

标签 javascript google-chrome-extension indexeddb

我正在为在线日语词典开发 Chrome 扩展,我正在尝试记录和显示用户的查询统计信息,以便他知道他最缺少哪些日语术语。

为此,我的目的是显示过去 X 天内查询最多的汉字(日语字符)。因此,我在扩展indexedDB中使用汉字/日期对和自动编号键创建了一个简单的对象存储,但似乎没有办法在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: 刃

对于用户。在按日期范围过滤后,只是对出现次数进行简单的计数,在本例中我没有这样做,因为时间戳在一小时内,而我的目的是过滤最近几天或几周。

最佳答案

我喜欢这个问题。我确信有人会有比我更好的答案,但这是一个随机的尝试。

首先,我应该指出一点,您在尝试将 event.target.result 分配给数据库时会遇到问题。您正在尝试将仅在其范围内有效的对象插入外部范围。这只会给你以后带来麻烦。我建议更多地了解 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

每个实例(记录)都包含一个唯一的字符。计数代表观察该 Angular 色的次数。 Last-observed 属性表示最近观察该 Angular 色的时间。

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

关于javascript - IndexedDB - 计算值出现次数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24416657/

相关文章:

javascript - React.js : Uncaught RangeError: Maximum call stack size exceeded

javascript - JS合并数组并划分合并值

javascript - 在 angularjs 页面中获取 mysql 结果

google-chrome-extension - 为什么我的 Chrome 扩展程序的操作图标显示在多功能框中的所有页面上?

javascript - indexedDB objectStore.get() 总是返回 undefined,尽管在 DB 中有结果

javascript - 如何对多个 Firebase 子节点进行平均投票?

javascript - Protractor - 将 JavaScript 注入(inject)测试页面

reactjs - 让源映射适用于使用 Create React App 构建的 Chrome 扩展

javascript - 使用多个条件查询

sqlite - 如何将 Dart 连接到 SQLite?