浏览器数据库 indexedDB 入门学习使用dexie.js封装
Publish: February 20, 2021 Category: WEB No Comments
基础知识可以在这里学习一下:
http://www.ruanyifeng.com/blog/2018/07/indexeddb.html 【浏览器数据库 IndexedDB 入门教程】
有一个对indexedDB的封装,https://github.com/dfahlander/Dexie.js 实现了丰富的操作。
1 快速入门:
1.1 数据库定义(declare database)
var db = new Dexie("MyDatabase");
db.version(1).stores({
friends: "++id, name, age, *tags",
gameSessions: "id, score"
});
提示: 不要在sql中声明所有的列,只需要声明需要建立索引的列,上面声明的几个列都是需要在where查询条件中要用到的列。
数据库定义语法
++ 自增主键(Auto-incermented primary key)
& 唯一(Unique)
* 多条目索引(Multi-entry index)
[A+B] 复合索引(Compound Index)
提示:
① indexedDB中的多条目索引是指数组属性的索引,其中数组中的每个项都指向object/record/document。它类似于PostgreSQL中的GIN索引。
② compound(或composite)索引是基于多个keypath的索引。它可以用于在一个索引中高效地索引多个属性,以便轻松找到两个键及其值的组合的存在性。在dexe中,复合索引必须在定义数据库模式的时候分配。
1.2 数据库升级(upgrade)
db.version(1).stores({
friends: "++id,name,age,*tags",
gameSessions: "id,score"
});
db.version(2).stores({
friends: "++id, [firstName+lastName], yearOfBirth, *tags", // 索引变更
gameSessions: null // 删除该表
}).upgrade(tx => {
// 只有在低于2版本的数据库中会执行以下操作
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;
});
});
上面的操作中首先在定义时指定的版本是'1',后面执行了一次升级到了'2’版本,upgrade回调中是具体的升级内容。
提示:
① IndexedDB 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。
1.2 类绑定 (Class binding)
class Friend {
// Prototype method
save() {
return db.friends.put(this); // Will only save own props.
}
// Prototype property
get age() {
return moment(Date.now()).diff (this.birthDate, 'years');
}
}
db.friends.mapToClass(Friend);
1.3 向数据库中添加数据
向数据库中添加一条和多条数据
await db.friends.add({name: "Josephine", age: 21});
await db.friends.bulkAdd([
{name: "Foo", age: 31},
{name: "Bar", age: 32}
]);
1.4 更新数据库中的数据
await db.friends.put({id: 4, name: "Foo", age: 33});
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});
1.5 删除数据
await db.friends.delete(4);
await db.friends.bulkDelete([1,2,4]);
const oneWeekAgo = new Date(Date.now() - 60*60*1000*24*7);
await db.logEntries
.where('timestamp').below(oneWeekAgo)
.delete();
1.6 查询数据
查询 数据中年龄在20-25之间,从第150行还是取25条数据,并以数组形式返回。
const someFriends = await db.friends
.where("age").between(20, 25)
.offset(150).limit(25)
.toArray();
查询name是josephine的并忽略大小写,并且迭代输出 frind内容。
await db.friends
.where("name").equalsIgnoreCase("josephine")
.each(friend => {
console.log("Found Josephine", friend);
});
查询name中以a,b,c,d开头并忽略大小写,以数组形式返回。
const abcFriends = await db.friends
.where("name")
.startsWithAnyOfIgnoreCase(["a", "b", "c"])
.toArray();
将age在0-18或者大于65的distance值更新为0.5。
await db.friends
.where('age')
.inAnyRange([[0,18], [65, Infinity]])
.modify({discount: 0.5});
查找所有name中包含字符‘a’忽略大小写的,并以数组形式返回
const friendsContainingLetterA = await db.friends
.filter(friend => /a/i.test(friend.name))
.toArray();
1.7 复合索引使用示例
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();
# 或者使用下面的方式
const forbundsKansler = await db.friends.get({
firstName: "Angela",
lastName: "Merkel"
});
// 该查询等同于:
// select * from friends where firstName='Angela' order by lastName
const angelasSortedByLastName = await db.friends
.where('[firstName+lastName]')
.between([["Angela", ""], ["Angela", "\uffff"])
.toArray()
await db.friends
.where('age').above(25)
.or('shoeSize').below(8)
.or('interests').anyOf('sports', 'pets', 'cars')
.modify(friend => friend.tags.push("marketing-target"));
1.8 检索前5项
const best5GameSession = await db.gameSessions
.orderBy("score").reverse()
.limit(5)
.toArray();
1.9 连接查询
var db = new Dexie('music');
db.version(1).stores({
genres: '++id,name',
albums: '++id,name,year,*tracks',
bands: '++id,name,*albumIds,genreId'
});
async function getBandsStartingWithA () {
// Query
const bands = await db.bands
.where('name')
.startsWith('A')
.toArray();
// Attach resolved properies "genre" and "albums" on each band
// using parallel queries:
await Promise.all (bands.map (async band => {
[band.genre, band.albums] = await Promise.all([
db.genres.get (band.genreId),
db.albums.where('id').anyOf(band.albumIds).toArray()
]);
}));
return bands;
}
1.10 存储二进制数据
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();
// Store the binary data in indexedDB:
await db.friends.put({
name: "David",
image: blob
});
}
1.11 IndexedDB2.0中二进制数据索引
var db = new Dexie("MyImgDb");
db.version(1).stores({
friends: "id, name" // 使用二进制UUID作为ID
});
// IndexedDB 2.0 允许索引 ArrayBuffer 和 XXXArray(typed arrays ) 不包括Blobs类型
async function playWithBinaryPrimKey() {
// 在indexedDB中存储二进制数据
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`);
}
}
1.12 IndexedDB 事务
await db.transaction('rw', [db.friends], async () => {
const friend = await db.friends.get(1);
++friend.age;
await db.friends.put(friend);
});
Related Posts:
- [尚无相关文章]