我正在为日语在线词典的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()});
}
包含示例数据的屏幕截图
在这种情况下,我想显示类似
的内容x3: 杉
x2: 刀, 尻
x1: 刃
对于用户。在我按日期范围过滤后,只是简单地计算出现的情况,在本例中我没有,因为时间戳在一小时内,我的目的是过滤最后几天或几周。
答案 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();
}
}
};
}