引用文档:
HTML5本地存储——IndexedDB(一:基本使用)
HTML5本地存储——IndexedDB(二:索引)
IndexedDB API
JavaScript高级程序设计(第三版)
在上一篇文章HTML5本地存储IndexedDB基础介绍(-)-数据库的简单增删改查向大家介绍了IndexedDB的简单增删改查,这篇文章将主要向大家介绍IndexedDB的游标与索引,通过游标与索引可以使得对于数据的查找更加方便,提高搜索速度
IndexedDB游标查询:
通过事务transaction
可以根据已知的键检索单个对象,当我们需要检索多个对象或者遍历时就需要在事务内部创建游标。游标是指向结果集的指针。与传统数据库的查询不同,游标不提前收集结果。游标指针会先指向结果中的第一项,在接到查找下一项的指令时,才会指向下一项。
在对象存储空间上调用openCursor()
方法可以创建游标,与IndexedDB
其它操作一样,openCursor()
方法返回的是IDBRequest
,因此需要在onerror
、onsuccess
事件中处理程序。代码示例如下:
var store = db.transaction(storename,'readwrite').objectStore(storename);
var request = store.openCursor();//db为IDBDatabase对象
request.onerror = function(e){
}
request.onsuccess = function(e){
console.log('游标开始查询')
var cursor = e.target.result;
if(cursor){//必须要检查
console.log(cursor);
cursor.continue();//遍历了存储对象中的所有内容
}else{
}
};
从上述代码中可以看到在onsuccess
事件处理程序中,有两行代码分别是:
var cursor = e.target.result
cursor.continue
e.target.result
可以取得存储空间的下一个对象,当结果集中有下一个对象时,e.target.result
是一个IDBCursor
实例,没有下一个对象则为空。所以我们在查询之前都要用if判断一下是否有这个对象IDBCursor
,下图为打印出来的cursor
,打印出来的实例有以下几个属性:
- direction:表示游标移动的方向
- key:对象的键
- value:查找出的对象
- primaryKey:游标使用的键,可能是对象键,或者是索引键(目前尚未建立索引,所以图中键来自于学生的id)
图中我们看到出现的实例是IDBCursorWithValue
而非上述所说的IDBCursor
,google中控制台直接打出的就是这样的情况,官方API文档说两者的区别在于IDBCursorWithValue
包含了value
属性。
cursor.continue
的作用在于使游标移动到结果集的下一项,默认情况下游标只发起一次请求,要想发起另一次请求使游标继续查找,则需调用
continue(key)
方法,该方法中参数可选,不指定参数,移到下一项,指定该参数,移到指定键的位置。
上述代码查找出结果如下,如果不加cursor.continue
则会只出现第一条数据:
IndexedDB游标更新、删除:
游标更新主要使用了cursor.update(value)
,用指定的对象更新当前游标的value
,代码如下:
function cursorUpdateData(db,storename){
//通过游标更新记录db为IDBDatabase对象,storename为存储空间名称
var store = db.transaction(storename,'readwrite').objectStore(storename);
var request = store.openCursor();
request.onsuccess = function(e){
console.log('游标开始查询')
var cursor = e.target.result,
value,
updateRequest;
if(cursor){//必须要检查
console.log(cursor);
if(cursor.key == 1002){
console.log('游标开始更新')
value = cursor.value;
value.age=38;
updateRequest = cursor.update(value);
updateRequest.onerror = function(){
console.log('游标更新失败');
};
updateRequest.onsuccess = function(){
console.log('游标更新成功');
}
}else{
cursor.continue();
}
}
};
}
游标删除主要使用了delete()
方法,主要代码如下:
function cursorDeldteData(db,storename){
//通过游标删除记录
var store = db.transaction(storename,'readwrite').objectStore(storename);
var request = store.openCursor();
request.onsuccess = function(e){
var cursor = e.target.result,
value,
deleteRequest;
if(cursor){
if(cursor.key == 1003){
deleteRequest = cursor.delete();//请求删除当前项
deleteRequest.onerror = function(){
console.log('游标删除该记录失败');
};
deleteRequest.onsuccess = function(){
console.log('游标删除该记录成功')
};
}else{
cursor.continue();
}
}
};
}
IndexedDB游标键范围:
键范围主要是在使用游标查询时增加一些条件限制,使得游标查询更加灵活。键范围由IDBKeyRange
实例表示,声明如下:
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange
IDBKeyRange
的方法如下:
-
IDBKeyRange.only(key)
该方法保证在查询时,只查询特定键,相当于直接访问存储空间并调用get(key)。 -
IDBKeyRange.lowerBound(key)
该方法指定结果集的下界,即从该key(包括key)开始查找,直到结束。 -
IDBKeyRange.lowerBound(key,true)
从该key的下一个对象开始查找(不包括该key所在对象),直到结束 -
IDBKeyRange.upperBound(key)
该方法指定结果集的上界,游标从头查找到该key(包括该key所在对象) -
IDBKeyRange.upperBound(key,true)
该方法指定结果集的上界,游标从头查找到该key的上一个对象为止(包括该key所在对象) -
IDBKeyRange.bound(keystart,keyend,bool,bool)
该方法同时指定上下界,4个参数含义分别为下界的键,上界的键,是否跳过下界,是否跳过上界。
//完整代码在最后,执行时请注意它们是异步的
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange
console.log('******************查找1004对象************')
var onlyKeyRange = IDBKeyRange.only(1004);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,onlyKeyRange);
console.log('******************查找从1004对象开始************');
var lowerBoundKeyRange = IDBKeyRange.lowerBound(1004);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,lowerBoundKeyRange);
console.log('******************查找从1004对象开始不包括1004************')
var lowerBoundKeyRangeTrue = IDBKeyRange.lowerBound(1004,true);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,lowerBoundKeyRangeTrue);
console.log('******************查找到1004对象结束************');
var upperBoundKeyRange = IDBKeyRange.upperBound(1004);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,upperBoundKeyRange);
console.log('******************查找到1004对象结束不包括1004************');
var upperBoundKeyRangeTrue = IDBKeyRange.upperBound(1004,true);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,upperBoundKeyRangeTrue);
console.log('******************查找到1002到1004对象************');
var boundKeyRange = IDBKeyRange.bound(1002,1004);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,boundKeyRange);
console.log('******************查找到1002到1004对象不包括1002************');
var boundKeyRangeLowerTrue = IDBKeyRange.bound(1002,1004,true);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,boundKeyRangeLowerTrue);
console.log('******************查找到1002到1004对象包括1002不包括1004************');
var boundKeyRangeUpperTrue = IDBKeyRange.bound(1002,1004,false,true);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,boundKeyRangeUpperTrue);
console.log('******************查找到1002到1004对象不包括1002不包括1004************');
var boundKeyRangeLTUT = IDBKeyRange.bound(1002,1004,true,true);
INDEXDB.cursorGetData(myDB.db,myDB.ojstore.name,boundKeyRangeLTUT);
IndexedDB索引
在建立存储空间时,指定的存储键可以有两种,一种是通过keyPath
指定存储键,另一种是通过autoIncrement
使记录自增,如果我们想为存储空间指定多个键要怎么办呢?IndexedDB提供了创建索引的方式,下面我们看一下如何创建索引以及索引的作用。
要创建索引,首先要引用对象存储空间,然后调用createIndex()方法,如下示例:
var store = db.createObjectStore("teachers",{keyPath:id});
var index = store.createIndex("age","age",{unique:false});
creatIndex()
的第一个参数是建立的索引的名字,第二个参数是索引的属性的名字,第三个参数是一个包含unique属性的选项的对象,表示这个索引的键在记录中是否唯一。(ps:测demo的时候发现创建索引应该和创建存储空间一起,如果先创建存储空间然后再获得存储空间创建索引会报错。)
根据索引创建游标:
根据索引创建游标的代码为store.index("age").openCursor(keyRange)
索引调用openCursor()
方法创建游标与存储空间对象直接创建游标区别如下图所示:
即
IDBCursorWithValue
实例属性key值不同。索引只是提供了不同的key值,增删改查仍由游标来完成
这里有一个不解的地方在于高程648页说key是对象的键,而primarykey是游标使用的键,按这种说法来说应该key中始终显示存储键"id":100x,primarykey中显示索引键或存储键,但是上图测试并不是这样,如果有知道的还请解答一下,谢谢。
根据索引键取得主键:
var key = store.index("age").getKey("30")
,此时返回的是该条记录的存储键,若记录有多条,只返回了第一条。
完整demo:
该demo可在控制台中执行函数,由于IndexedDB API的异步进行,如果所有函数同时执行,打印出来的信息会不按说明排列,建议想测试哪个功能在控制台中执行即可。默认功能为建立打开数据库、创建存储空间,创建索引、添加数据。
ps:文章有错误或者不足之处,还请指出,还请多多指教
个人博客:
进击的程序茗