Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说index数据库程序用法_dbvar数据库,希望能够帮助你!!!。
A Minimalistic Wrapper for IndexedDB
这是官网的一句话翻译过来就是IndexedDB 的一个最小化包装
Dexie使用本机IndexedDB API解决了三个主要问题:
有使用过indexDB的同学就知道其查询语句的麻烦特别是多条件查询的时候
这是Dexie的官网https://dexie.org/,
Dexie表现出色。 它的批量方法利用了IndexedDB中一个鲜为人知的特性,可以在不收听每个onsuccess事件的情况下存储东西。 这样可以最大限度地提高性能。
模块化开发下可以使用npm/cnpm/yarn安装
npm install dexie
而想直接引入使用的也可以使用以下方法
<script src="https://unpkg.com/dexie@latest/dist/dexie.js"></script>
这里我采用了一下官网的一个简单的例子
//模块化开发下需要引入该组件
import Dexie from 'dexie'
//创建一个数据库 若数据库已存在则为打开
//打开数据库时,会判断当前version值是否大于已经存在的version值,若大于则会upgrade即升到最高版本
var db = new Dexie("test_db");
db.version(1).stores({
student: 'name,age'
});
db.open()
//写入一些数据
db.student.put({
name: "小明", age: 18}).then (function(){
//当数据存储完成后 我们可以读取它
return db.student.get('小明');
}).then(function (data) {
console.log("我是小明,今年 " + data.age);
}).catch(function(error) {
//最后别忘了抓住任何可能发生在上面的代码块。
console.log("error: " + error);
db.close()
});
db.close()
//注意:不要像在SQL中那样声明所有列。只声明要索引的属性,即要在where(…)查询中使用的属性。
var db = new Dexie("MyDatabase");
db.version(1).stores({
friends: "++id, name, age, *tags",
gameSessions: "id, score"
});
++ | 自动递增主键 |
& | 唯一主键 |
* | 多条目索引 |
+ | 复合索引 |
第一第二栏目就不说了很好理解,这里主要说明一下第三第四栏
var db = new Dexie('dbname');
db.version(1).stores ({
books: 'id, author, name, *categories'
});
在本示例中,书籍可以按多个类别进行分类。这是通过让book对象具有一个名为“categories”的数组属性来实现的,该数组属性包含类别字符串。见以下示例:
db.books.put({
id: 1,
name: 'Under the Dome',
author: 'Stephen King',
categories: ['sci-fi', 'thriller']
});
在示例中,我们添加了一本包含多个类别“科幻”和“惊悚”的书。注意,不仅字符串可以放入数组,而且任何可索引类型都是有效的。
所有where子句运算符都可用于查询多条目索引对象。但是,运算符的行为不像普通索引那样直观。例如,应该使用WhereClause.equals()运算符查询属于特定类别的书籍,而更具语义的名称可能是contains()。这样做的原因是要映射indexedDB在本机上的工作方式,还允许使用任何运算符,而不将多条目索引绑定到某些运算符。
// 查询所有科幻书籍:
function getSciFiBooks() {
return db.books
.where('categories').equals('sci-fi')
.toArray ();
}
查询多条目索引时,如果同一项有多个索引匹配,则可能会得到同一对象的多个结果。因此,在对多条目索引的查询中始终使用Collection.distinct()是一个很好的做法。
// 定义数据库
var db = new Dexie('dbname');
db.version(1).stores ({
books: 'id, author, name, *categories'
});
// 插入一本多类别的书
db.books.put({
id: 1,
name: 'Under the Dome',
author: 'Stephen King',
categories: ['sci-fi', 'thriller']
});
// 查询所有科幻书籍:
function getSciFiBooks() {
return db.books
.where('categories').equals('sci-fi')
.toArray ();
}
// 查询所有科幻或浪漫书籍:
function getSciFiOrRomanceBooks() {
return db.books
.where('categories').anyOf('sci-fi', 'romance')
.distinct() // 筛选掉重复的数据
.toArray()
}
// 复杂查询
function complexQuery() {
return db.books
.where('categories').startsWithAnyOfIgnoreCase('sci', 'ro')
.or('author').equalsIgnoreCase('stephen king')
.distinct()
.toArray();
}
以下浏览器不支持多条目索引:
复合索引是基于多个键路径的索引。它可以有效地为一个索引中的多个属性建立索引,以方便地找到两个键的组合及其值的存在性。
定义架构时必须指定复合索引:
var db = new Dexie('dbname');
db.version(1).stores({
people: 'id, [firstName+lastName]'
});
在上面的示例中,firstName和lastName属性中包含有效键的记录将被索引。如果存储了具有属性{firstName:‘foo’,lastName:‘bar’}的对象,则可以使用以下方法有效地查找该对象:
db.people.where('[firstName+lastName]').equals(['foo', 'bar'])
//或者下面这样
db.people.where({
firstName: 'foo', lastName: 'bar'})`
第二种写法是一个特例,它只在Dexie>=2.0中工作,并且可以通过多个属性进行匹配,无论您的浏览器是否支持复合查询。
附赠官网的语法文档
db.version(1).stores({
friends: "++id,name,age,*tags",
gameSessions: "id,score"
});
db.version(2).stores({
friends: "++id, [firstName+lastName], yearOfBirth, *tags", // 更改索引
gameSessions: null // Delete 对象仓库
}).upgrade(tx => {
// 仅当安装了低于2的version时才会执行
return tx.table("friends").modify(friend => {
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
friend.birthDate = new Date(new Date().getFullYear() - friend.age, 0);
delete friend.name;
delete friend.age;
});
});
附上有关数据库版本控制的详细信息
class Friend {
// Prototype method
save() {
return db.friends.put(this); // 只保存自己的 props.
}
// Prototype property
get age() {
return moment(Date.now()).diff(this.birthDate, 'years');
}
}
db.friends.mapToClass(Friend);
await db.friends.add({
name: "Josephine", age: 21});
//or
await db.friends.bulkAdd([
{
name: "Foo", age: 31},
{
name: "Bar", age: 32}
]);
item | 要添加的对象 | |
---|---|---|
key | 主键 | option |
注意
将给定对象添加到存储。如果已经存在具有相同主键的对象,则操作将失败,并将使用错误对象调用返回的promise catch()回调。如果操作成功,则返回的promise then()回调将接收对象存储区上的add请求的结果,即插入对象的id。
只有当表使用非入站键时,才必须使用可选的第二个键参数。如果在具有入站密钥的表上提供密钥参数,则操作将失败,返回的承诺将被拒绝。
item | 要添加的对象数组 |
---|---|
keys (非必填) | 对应于给定项数组的主键数组 |
option(非必填) | {allKeys?: boolean} 如果指定{allKeys:true},则返回值将是结果主键的数组,而不是上一次添加的主键。如果表使用入站键,则可以将选项作为第二个参数提供。API将知道第二个参数是通过类型检查表示选项还是键数组。 |
何时使用keys参数
var db = new Dexie("test");
db.version(1).stores({
tableWithInboundKeys: "id,x,y,z", // 不能提供 "keys"
tableWithAutoIncNonInbound: "++,x,y,x", // 可选 "keys"
tableWithoutInboundKeys: ",x,y,z" // 必需提供 "keys"
});
如果有大量对象要添加到对象存储中,那么bulkAdd()比在循环中执行add()要快一点。
await db.friends.put({
id: 4, name: "Foo", age: 33});
//or
await db.friends.bulkPut([
{
id: 4, name: "Foo2", age: 34},
{
id: 5, name: "Bar2", age: 44}
]);
await db.friends.update(4, {
name: "Bar"});
await db.customers
.where("age")
.inAnyRange([ [0, 18], [65, Infinity] ])
.modify({
discount: 0.5});
item | 要添加的对象 | |
---|---|---|
key | 主键 | option |
注意
如果已存在具有相同主键的对象,则该对象将替换为给定对象。如果它不存在,则将添加它。
只有当表使用非入站键时,才必须使用可选的第二个键参数。如果在具有入站密钥的表上提供密钥参数,则操作将失败,返回的rejection promise。
item | 要put的对象数组 |
---|---|
keys (非必填) | 对应于给定项数组的主键数组 |
option(非必填) | {allKeys?: boolean} 如果指定{allKeys:true},则返回值将是结果主键的数组,而不是上一次添加的主键。如果表使用入站键,则可以将选项作为第二个参数提供。API将知道第二个参数是通过类型检查表示选项还是键数组。 |
key | 主键 |
---|---|
changes | 对象,该对象包含要更改的每个属性的键路径。 |
返回值:0/1
Promise 更新记录的数量(如果对象已更新,则为1,否则为0)。结果为0的原因可能是找不到提供的密钥,或者提供的数据与现有数据相同,因此没有更新任何内容。
表示数据库对象的集合。注意,它本身不包含任何对象。相反,它为如何执行数据库查询做了准备。调用返回Promise的方法时将执行查询,例如toArray()、keys()、count()或each()。
将基于JS的条件添加到集合
在进一步操作查询之前克隆该查询(不克隆数据库项)。
获取集合中的项目数
删除集合中的所有对象
按降序排序
删除具有相同主键的项的重复项
执行查询并为每个项调用函数
对正在使用的索引或主键执行查询,并为每个键调用一个函数
对索引执行查询,并为对应于索引的每个主键调用函数。
对正在使用的索引或主键执行查询,并为每个唯一键调用函数
筛选对象
获取集合中的第一个项目
检索包含集合的所有键的数组(索引键或主键取决于where()子句)
获取集合中的最后一项
将结果限制为给定的项目数
使用给定的属性或函数修改集合中的所有对象。
忽略给定偏移量前的N项并返回其余项
逻辑或运算
检索包含集合的所有主键的数组
不要通过阅读挂钩过滤结果
颠倒项目顺序。
执行查询并获取结果按给定属性排序的数组
执行查询并获取一个数组,其结果按where()子句中使用的索引排序
检索包含集合的所有唯一键(索引键或主键取决于where()子句)的数组
忽略给定筛选器返回true后发生的项。
changes | 对象,其中包含要应用于集合中所有对象的更改。调用方可以提供函数而不是对象 |
注意
如果给定的更改是一个对象,则对象中的每个键表示一个keyPath,每个值表示要设置的新值。键路径可以是属性的名称,或者如果包含句点(.),则充当嵌套对象中属性的路径。
如果值是函数,则将为每个对象调用该函数,以便该函数可以修改或删除对象上的任何属性。函数也可以使用this.value=otherObject将对象替换为另一个对象。最后,函数还可以通过delete this.value删除对象;请参见下面的示例。
警告
Safari 10和11有一个问题,如果使用dexie@2,那么这个方法基本上会停止处理使用索引的查询(与dexie where子句一样)。Dexie@3解决了这个问题。德克西594期正在讨论这个问题
await db.friends.delete(4);
await db.friends.bulkDelete([1,2,4]);
主键 | 要删除的对象的主键 |
keys | 要删除的对象的主键数组 |
const oneWeekAgo = new Date(Date.now() - 60*60*1000*24*7);
await db.logEntries
.where('timestamp').below(oneWeekAgo)
.delete();
删除查询出的数据
成功则返回删除的数量Promise()
如果未能删除任何对象或回调函数中发生异常,则整个操作将失败,事务(transaction ())将中止。
如果捕捉到返回的承诺,事务将不会中止,并且您将收到一个包含以下属性的Dexie.mulmodifyerror对象:
failures | 发生的所有错误的错误对象数组 |
---|---|
failedKeys | 具有失败删除的键的数组。这个数组的顺序与failures相同,因此failures[i]总是表示failedKeys[i]的失败 |
successCount | 成功删除的次数。 |
如果要记录错误,但仍要中止事务,则必须将操作封装在transaction()块中,然后捕获事务。也可以捕获该操作并在catch()子句中调用transaction.abort()。
const someFriends = await db.friends
.where("age").between(20, 25)
.offset(150).limit(25)
.toArray();
await db.friends
.where("name").equalsIgnoreCase("josephine")
.each(friend => {
console.log("Found Josephine", friend);
});
const abcFriends = await db.friends
.where("name")
.startsWithAnyOfIgnoreCase(["a", "b", "c"])
.toArray();
await db.friends
.where('age')
.inAnyRange([[0,18], [65, Infinity]])
.modify({
discount: 0.5});
const forbundsKansler = await db.friends
.where('[firstName+lastName]')
.equals(["Angela", "Merkel"])
.first();
在Dexie2.0中,您可以简单地执行上面的查询:
const forbundsKansler = await db.friends.where({
firstName: "Angela",
lastName: "Merkel"
}).first();
//or
const forbundsKansler = await db.friends.get({
firstName: "Angela",
lastName: "Merkel"
});
此查询等于:从firstName='Angela’按姓氏排序的朋友中选择所有
const angelasSortedByLastName = await db.friends
.where('[firstName+lastName]')
.between([["Angela", ""], ["Angela", "\uffff"])
.toArray()
选择成绩前五的数据
const best5GameSession = await db.gameSessions
.orderBy("score").reverse()
.limit(5)
.toArray();
通过创建WhereClause实例开始筛选对象存储。
// Dexie 1.x and 2.x:
table.where(indexOrPrimaryKey)
// Dexie 2.x only:
table.where(keyPathArray);
table.where({
keyPath1: value1, keyPath2: value2, ...});
Parameters
indexOrPrimaryKey: String | 在Version.stores()中注册的索引或主键的名称。特殊字符串“:id”表示主键。 |
keyPathArray | (Dexie 2.x only)识别要筛选的键槽的字符串。必须与复合索引或主键匹配。 |
{keyPath1: value1, keyPath2: value2, …} | (Dexie 2.x only)过滤准则 |
表示索引或主键上的筛选器。
返回索引位于给定键之上的对象集合
返回索引高于或等于给定键的对象集合
返回一个对象集合,其中索引等于给定数组中的任何键
返回一个对象集合,其中索引与任何给定字符串匹配,忽略大小写差异。
返回索引低于给定键的对象集合
返回索引低于或等于给定键的对象集合
返回索引位于给定边界之间的对象集合
返回索引等于给定键的对象集合
返回一个对象集合,其中索引等于给定的字符串键,忽略大小写差异
返回索引在任何给定范围内的集合。
返回一个集合,其中index等于给定数组中任何键以外的任何键
返回一个集合,其中index不等于给定值
返回一个对象集合,其中索引以给定的字符串键开头
返回一个对象集合,其中索引以任何给定字符串开头
返回一个对象集合,其中索引以给定的字符串键开头,忽略大小写差异
返回一个对象集合,其中索引以任何给定字符串开头,忽略大小写差异
var db = new Dexie("MyImgDb");
db.version(1).stores({
friends: "name"
});
// 下载并存储图片
async function downloadAndStoreImage() {
const res = await fetch("some-url-to-an-image.png");
const blob = await res.blob();
await db.friends.put({
name: "David",
image: blob
});
}
IndexedDB 2.0包含对索引二进制数据的支持。Chrome和Safari以及部分Firefox支持这个规范(Firefox在使用二进制主键时有一个bug,但是在使用二进制索引时效果很好)。
var db = new Dexie("MyImgDb");
db.version(1).stores({
friends: "id, name" // 使用二进制UUID作为id
});
// IndexedDB 2.0 允许索引ArrayBuffer和XXXArray
// (类型化数组,但不是blob)
async function playWithBinaryPrimKey() {
// 存储二进制数据:
await db.friends.put({
id: new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]),
name: "David"
});
// 通过二进制搜索检索
const friend = await db.friends.get(
new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]));
if (friend) {
console.log(`Found friend: ${
friend.name}`);
} else {
console.log(`Friend not found`);
}
}
一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
await db.transaction('rw', [db.friends], async () => {
const friend = await db.friends.get(1);
++friend.age;
await db.friends.put(friend);
});