HTML5本地存储IndexedDB基础介绍(二)- 游标和索引

引用文档:

HTML5本地存储——IndexedDB(一:基本使用)
HTML5本地存储——IndexedDB(二:索引)
IndexedDB API
JavaScript高级程序设计(第三版)

在上一篇文章HTML5本地存储IndexedDB基础介绍(-)-数据库的简单增删改查向大家介绍了IndexedDB的简单增删改查,这篇文章将主要向大家介绍IndexedDB的游标与索引,通过游标与索引可以使得对于数据的查找更加方便,提高搜索速度

IndexedDB游标查询:

通过事务transaction可以根据已知的键检索单个对象,当我们需要检索多个对象或者遍历时就需要在事务内部创建游标。游标是指向结果集的指针。与传统数据库的查询不同,游标不提前收集结果。游标指针会先指向结果中的第一项,在接到查找下一项的指令时,才会指向下一项。

在对象存储空间上调用openCursor()方法可以创建游标,与IndexedDB其它操作一样,openCursor()方法返回的是IDBRequest,因此需要在onerroronsuccess事件中处理程序。代码示例如下:

            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则会只出现第一条数据:

HTML5本地存储IndexedDB基础介绍(二)- 游标和索引_第1张图片

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);
HTML5本地存储IndexedDB基础介绍(二)- 游标和索引_第2张图片

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:文章有错误或者不足之处,还请指出,还请多多指教
个人博客:
进击的程序茗

你可能感兴趣的:(HTML5本地存储IndexedDB基础介绍(二)- 游标和索引)