indexedDB 操作库IDBWRAPPER 教程翻译及API翻译第二部分part2

这是这个系列教程的第二部分,也是最后一部分,第一部分教程请点击这里

While the last part of the tutorial covered the basic CRUD methods get/getAll/put/delete, this part is about the real thing: running queries against the store.

To do so, we need to get familiar with two things: Creating indexes, and creating keyRanges.

 

上一讲,我们讲了几个基础操作API 方法 get/getAll/put/delete, 这一讲,来点干货:操作store

为此,咱先得熟悉两个事情:

创建indexes索引和创建keyRanges 可理解为limit、 where等条件的综合体吧

 

 

CREATING INDEXES(创建索引)

Every store has an implicit index, which is the keyPath of the store (think of it as the primary index). If you want to run queries against other keys of your stored objects, you need to add an index for that property. A store can have unlimited indexes.

To create an index, you need to add an object containing information about the index to the indexes array of the options object in the IDBStore constructor. For example:

每个store都有一个隐式的index索引,就是storekeyPath(可以理解为一般数据库的主索引primary index.如果你想通过其它key(对象属性)运行查询语句操作store,那就得另为那个属性添加一个index.一个store对象可以创建无限个索引

要创建一个index, 你得添加一个包含此索引信息的对象并添加至indexes数组,并将indexes 作为参数传入IDBStore构架函数。举个栗子:

customers = new IDBStore({
  dbVersion: 1,
  storeName: 'customer-index',
  keyPath: 'customerid',
  autoIncrement: true,
  onStoreReady: refreshTable,
  indexes: [
    { name: 'lastname', keyPath: 'lastname', unique: false, multiEntry: false }
  ]
});

The index options object(索引对象参数)

The name property is the identifier of the index. If you want to work with the created index later, this name is used to identify the index. This is the only property that is mandatory.

The keyPath property is the name of the property in your stored data that you want to index. If you omit that, IDBWrapper will assume that it is the same as the provided name, and will use this instead.

The unique property tells the store whether the indexed property in your data is unique. If you set this to true, it will add a uniqueness constraint to the store which will make it throw if you try to store data that violates that constraint. If you omit that, IDBWrapper will set this to false.

The multiEntry property is kinda weird. You can read up on it here. However, you can live perfectly fine with setting this to false (or just omitting it, this is set to false by default).

So, the above index options object could have also been written like this:

Name属性 是此index对象的标识。如果你后面要操作此indexname常常被用来标明此index对象,这是唯一强制需要的一人个属性

keyPath 属性 是你想通在数据库中数据的某个属性名索引的名称(可理解为字段名).如果你忽略了,那么IDBWrapper会分配一个与name相同的名称给keyPath

Unique属性 告诉store此索引属性在你的数据中是否是唯一的,如果你设置为true, 则会给store添加上唯一性约束功能,如果你存进一条数据有相当属性值的数据进store, store就会抛出错误信息。如果你忽略此属性,IDBWrapper则会默认设置其为false

 

multiEntry属性 有些怪,你自己去查资料吧。其实你可以忽略它,它默认设置是false

通过上面的介绍,indexes其实可以这样设置:

indexes: [
  { name: 'lastname' }
]

Handy, isnt it?

超简单吧?

QUERYING THE STORE(操作吧)

As we now have indexes, we can start iterating over datasets. To do so, IDBWrapper provides an iterate() method. It takes to arguments: the first is the onItem callback, which is called for each entry in the store that matched the query. The second argument is an options object where you can add more specific instructions for your query. This second argument is optional; if you omit it, IDBWrapper will iterate over all entries in the store and return results ordered by the store’s keyPath, in ascending order.

现在咱有了indexes参数对象了。可以开始遍历数据集了。为此,IDBWrapper提供了iterate()方法,它需要两个参数:第一个参数onItem 回调,它是在store查询到符合条件的数据(词目)后就会被调用。第二个是对象类型的参数,它可以让你更详细的设置query查询。第二个参数是可选的,如果你忽略了,IDBWrapper会遍历所有数据并根据keyPath升序排列后返回

customers.iterate(onItem, {
  index: 'lastname',
  keyRange: IDBKeyRange,
  order: 'ASC',
  filterDuplicates: false,
  writeAccess: false,
  onEnd: onEndCallback,
  onError: onErrorCallback
});

The onItem callback

The provided callback will be called once for every match. It will receive three arguments: the object that matched the query, a reference to the current cursor object (IDBWrapper uses IndexedDB’s Cursor internally to iterate), and a reference to the current ongoing transaction.

There’s one special situation: if you didn’t pass an onEnd handler in the options objects (see below), the onItem handler will be called one extra time when the transaction is over. In this case, it will receive null as only argument. So, to check when the iteration is over and you won’t get any more data objects, you can either pass an onEnd handler, or check for null in the onItem handler.

onItem回调会在找到每一条符合记录数据时都会被调用,它会接受三个参数:

1、符合条件的数据对象

2、当前对象的游标引用(IDBWrapper使用IndexedDB内部的Cursor游标来遍历)

3、当前进行的transcation事务对象

此处有一个特殊情况,如果你不在参数中传onEnd回调,那么在onItem回调函数会在事务结束后被多调用一次,这种情况下,它只会收到一个null参数。所以在遍历数据的时候为避免这样的情况,你得传一个onEnd回调或者在onItem中对NULL做特别的过滤

The iterate options object(遍历方法所需要的参数对象)

The index property contains the name of the index to operate on. If you omit this, IDBWrapper will use the store’s keyPath as index.

In the keyRange property you can pass a keyRange; forget about that for now, we’ll come to keyRanges in a minute.

The order property can be set to ‘ASC’ or ‘DESC’, and, you might have guessed so, determines the ordering direction of results. If you omit this, IDBWrapper will use ‘ASC’.

The filterDuplicates property is an interesting one: If you set this to true (it defaults to false), and have several objects that have the same value in their key, the store will only fetch the first of those. It is not about objects being the same, it’s about their key being the same. For example, in the customers database are a couple of guys having ‘Smith’ as last name. Setting filterDuplicates to true in the above example will make iterate() call the onItem callback only for the first of those.

The writeAccess property defaults to false. If you need write access to the store during the iteration, you need to set this to true. But, for now, just forget about this, we’ll come to this later.

In the onEnd property you can pass a callback that gets called after the iteration is over and the transaction is closed. It does not receive any arguments.

In the onError property you can pass a custom error handler. In case of an error, it will be called and receives the Error object as only argument.

Index属性 包含了索引名称,会在索引时起作用。如果你忽略掉,则系统会将storekeyPath做为索引.

 

keyRange属性,先忘了它吧,马上会讲到的

Order属性可以设置为ASC升序或DESC降序,你可能已经猜到了,它是确定查询结果的排序的。如果忽略掉则IDBWrapper会默认为ASC升序

filterDuplicates 属性比较有趣,如果你设置为true(默认为false),并且有多个相同值的属性对象,store只会匹配最前面的一个。这不是关于对象是否相同,而是它们的key值是否相同。举个栗子,在customers数据库中有一对哥们儿的last name都叫Smith,设置filterDuplicates true,在上面的例子中使用iterate(),它的onItem回调中只会得到第一个Smith

writeAccess属性默认为false, 如果你需要在遍历过程中修改数据,那你就得设置它为true了,但现在忘了它吧,后面马上会讲到

onEnd属性可以传个回调,它会在遍历完成并且事务结束关闭后被调用,它不会接受到任何参数

onError属性,你可以传处自定义的错误处理函数,如果发生错误,则会被调用并且接受到错误一个对象

LET’S START RUNNING QUERIES!(开始操作吧)

There’s a couple of things we can already do at this point. We can, for example:

- get all customers, ordered by their customer id, in a descending manner

- get a list of all different last names our customers have

While this is better than just get() or getAll(), we definitely want to be more specific in our queries. Time to meet keyRanges.

在此处我们已经可以做两件事情了,兴个栗子:

-得到所有customers数据,通过id降序方式排序

-得到所有last name不相同的数据

这会比get()或者getAll()给力吧,我们清楚的知道想要更多特殊的操作在queries中,是时候见一见keyRanges属性了

KEYRANGES(query操作影响的范围)

IndexedDB allows you to specify a range of keys to use as condition to check whether a key matches or not. For example, a condition can be (key <= 1000) which would return everything that has a key with a value of less that 1000, including 1000 as well. This range has an “upper bound”. A range can also have a lower bound (key > 25), or a lower and an upper bound (key > 25 && key <= 1000). IDBWrapper provides a makeKeyRange() method to create a keyRange. Let’s see an example:

IndexedDB 允许你定义特殊的范围属性,作为判断数据是否符合条件,兴趣个栗子,(key<=1000)它就公返回所有key对应值小于等于1000的数据。这样的范围就是upper bound。范围也能大于并且小于等于某个值。IDBWrapper 提供了makeKeyRange() 方法创建keyRange对象。来看栗子吧:

var myKeyRange = customers.makeKeyRange({
  lower: 'A',
  excludeLower: false,
  upper: 'M',
  excludeUpper: true
});

This range will match against all keys starting with ‘A’ to ‘L’. The excludeUpperproperty is set to true, which means that a key that exactly matches the upper bound will be excluded from the result. The exclude[Lower/Upper] properties are set to false by default.

We can now use the newly created keyRange with the iterate() method and pass it in the option object’s keyRange property:

这个范围会匹配所有keyAL的数据记录,excludeUpper属性设置为true是指等于L的值在结果中会被排除掉,exclude[Lower/Upper] 两个属性默认皆为false

现在咱就可以使用新创建的keyRange (myKeyRange)iterate()方法,将keyRange  (myKeyRange)作为iterate参数对象中的keyRange属性:

 

customers.iterate(onItem, {
  index: 'lastname',
  keyRange: myKeyRange,
  order: 'ASC',
  filterDuplicates: false,
  writeAccess: false,
  onEnd: onEndCallback,
  onError: onErrorCallback
});

 

This will fetch all customers from the store, that have their last name beginning with ‘A’ to ‘L’. As the lastname keys in our example all start with uppercase letters, we can also define the keyRange like this:

这样会在store中匹配所有last name A开始到L结束的customers,在我们的例子中都以大写字母开始。

 

我们其实也可以这么干

 

var myKeyRange = customers.makeKeyRange({
  upper: 'M',
  excludeUpper: true
});

With keyRanges, we can do more interesting queries:

- Get all customers who’s last name is ‘Doe’

- Get a list of different last names starting with ‘G’ or higher.

That’s all IndexedDB offers out of the box regarding queries. But, if you are creative, you can do some fancy queries with it. And, in many cases it saves you from fetching all data from the store and manually reducing the result set.

有了keyRanges,我们可以做更多有趣的操作

-得到所有last name为‘Doe’的customers

-得到last names不同且开始于G或更高 ???

这是所有IndexedDB提供出来的queries,但是如果你有创意,你可以做更多不可思议的操作。在许多情况下它保存得到的数据,手功删减结果集中的数据

USING KEYRANGES ELSEWHERE(在其它地方使用KeyRanges )

KeyRanges can be used instead of a key with many functions that accept a key as argument. While there are useful appliances of this, e.g.customers.delete(customers.makeKeyRange({lower: 100});, which would delete all customers with a customerid greater than 100, the spec is not very clear about whether this is to be implemented by browsers or not; so I’d rather not rely on this.

很多方法都可以接受KeyRanges对象作为key参数对象。这非常有用,比如:customers.delete(customers.makeKeyRange({lower: 100});这样操作就会删掉所有customerid大于100的数据项,只是这样做不清楚是不是实现于浏览器,所以我太这样做

ITERATION AND TRANSACTIONS (遍历与事务)

During the iteration, there is an open transaction running. IDBWrapper tries to keep you away from all this transaction stuff so that you don’t have to care about it, but you still need to be aware of this. There are two transaction modes: read-only and read-write. By default, IDBWrapper uses a read-only transaction for iteration. Thing is, in an onItem callback, you are inside a transaction; that means, that if you want to read or write to the store using put/delete/etc (which will try to open yet another transaction) inside of the onItem handler, funny things will happen. This scenario is kind of underspecified and browsers may do different things then.

If you need to modify data during the onItem handler (say, you query the store for all customers older than 50 years and want to add a ‘senior’ property to them), this is how you need to do it:

First, you need to set the writeAccess property to true in the options obect. Then, in your onItem handler, you need to use the cursor object to change data. It offers two methods, update() and delete(). Both will return an IDBRequest object. An example:

iterate遍历过程中,会有一个开放的事务(transaction)在跑,IDBWrapper 尽量保持不需要你干预事务相关的操作,所以你不需要关心它,但你还是需要知道它。事务存在两种模式:只读(read-only)和读写(read-write)

IDBWrapper 默认使用只读模式,事务存在于onItem回调中,这意谓着如果你想在onItem中使用put/delete/etc,有趣的事就这样发生了。这种方案W3C还没有最终确定,可能将来浏览器实现中会修改也说不定

如果你在onItem中需要修改数据(如:你想在年纪大于50岁的客户中添加一个senior属性),这就是为什么你需要它

首先你得在创建keyRanges对象时设置writeAccess属性值为true,然后在 onItem回调中你需要使用游标(cursor)对象来改变数据。游标对象提供两个方法 update() delete().两个都会返回IDBRequest 对象,来个栗子:

var onItem = function(dataObj, cursor, transaction){
  if(dataObj.age < 18){
    var deleteRequest = cursor.delete(); // request deletion of current object
    deleteRequest.onsuccess = function(evt){ /* ... */ };
    deleteRequest.onerror = function(err){ /* ... */ };
  }
 
  if (dataObj.age >= 50) {
    dataObj.isSenior = true;
    var updateRequest = cursor.update(dataObj); // request to overwrite object with object passed to update() method
    updateRequest.onsuccess = function(evt){ /* ... */ };
    updateRequest.onerror = function(err){ /* ... */ };
  }
 
}

EXAMPLES(下面是各种操作的例子)

Get all customers, ordered by their customer id, in a descending manner

获取所有数据、根据id倒序

var onItem = function (item) {
  console.log('got item:', item);
};
var onEnd = function (item) {
  console.log('All done.');
};
 
customers.iterate(onItem, {
  order: 'DESC',
  onEnd: onEnd
});

Get a list of all different last names our customers have

获得last names不相同的客户数据

var onItem = function (item) {
  console.log('got item:', item);
};
var onEnd = function (item) {
  console.log('All done.');
};
 
customers.iterate(onItem, {
  index: 'lastname',
  filterDuplicates: true,
  onEnd: onEnd
});

Get all customers who’s last name is ‘Doe’

获得所有last name Doe的客户数据

var onItem = function (item) {
  console.log('got item:', item);
};
var onEnd = function (item) {
  console.log('All done.');
};
 
var keyRange = customers.makeKeyRange({
  lower: 'Doe',
  upper: 'Doe'
});
 
customers.iterate(onItem, {
  index: 'lastname',
  keyRange: keyRange,
  onEnd: onEnd
});

Get a list of different last names starting with ‘G’ or higher.

var onItem = function (item) {
  console.log('got item:', item);
};
var onEnd = function (item) {
  console.log('All done.');
};
 
var keyRange = customers.makeKeyRange({
  lower: 'G'
});
 
customers.iterate(onItem, {
  index: 'lastname',
  keyRange: keyRange,
  filterDuplicates: true,
  onEnd: onEnd
});

=========================== my name is 分割 ===============================

作者的博客,也是教程地址,英文版的http://jensarps.de/2012/11/13/working-with-idbwrapper-part-2/

=========================== my name is 分割===============================

本人英文水平绝对有限,入门后还请看英文版的官方博客哟。

注:转载请注明出处:偷饭猫email: xiaodong1986@me.com

 

 

 

 

 

原文地址:https://www.cnblogs.com/willian/p/2951552.html