跳至主要內容

db#数据库

Thisky大约 4 分钟

tsbApi.db.* API

由于传统的web数据库存储方式无法达到更好的数据存储和持久化效果,且容易被清理浏览器缓存时误杀,所以我们提供了db接口,方便大家的应用做持久化。

db接口采用PouchDB(pdb)做底层实现,并提供了pdb的常规接口。具体可参考文档。

注意:
1.pdb本身是一个数据库适配器,他在不同的环境下会使用不同的底层。例如在浏览器web下使用indexDB,而在nodejs下使用levelDB,而我们轻应用则统一采用与nodejs一致的levelDB方式进行存储。

强烈建议大家在使用db之前,先去看一下clipboard.ts的写法,大部分的分页用法都有示例。可以直接cccv,大大提升编写效率。
vite/packages/table/apps/clipboard/store.ts

2.由于levelDB只可在一个进程中使用。所以如果卡片与主应用采用长连接方式会锁住数据库,造成被占用后另一个无法读写数据库。
为了解决此冲突问题,所有的数据库操作,都是采用先连库后关闭的方式。每次操作都会释放掉数据库。所以应用开发者需要考虑到这个问题。
尽量规避掉需要长时间操作的操作,同时也要对数据库异常进行判断,避免出现死锁导致操作失败。

db操作

tsbApi.db.put(doc)

//创建
tsbApi.db.put({
  _id:'item:1',
  category:'cat1',
  content:'content',
  createTime:Date.now(),
  updateTime:Date.now()
})
//更新
tsbApi.db.put({
  _id:'item:1',
  content:'content2',
  updateTime:Date.now(),
  ...,
  _rev:'...'//此字段应当从数据库内获取最新的数据得到,而不可手写
})

_id是文档的唯一标志,推荐采用命名规则[表名]:[nanoid],例如item:djfexe,nanoid不容易冲突,但是易读性较差,且没有规律
更新特别注意事项:pdb要求在更新的时候,数据必须提供_rev字段,且此字段与数据库内数据最新的字段相同,否则无法写入。这是一种防止版本冲突的方式。
所以在更新之前请先试用获取方法获取到最新的数据,然后修改需要更新的字段,再使用put更新。

tsbApi.db.bulkDocs(docs)

批量添加文档

tsbApi.db.bulkDocs([
  {
    _id:'item:1',
    ...
  },
  {
    _id:'item:2',
    ...
  }
])

tsbApi.db.remove(id)

删除某个文档

//删除文档
tsbApi.db.remove('item:1')

tsbApi.db.allDocs(key)

//取回以item:开头的全部文档
tsbApi.db.allDocs('item:')

//取回指定id的内容
tsbApi.db.allDocs(['item:1','item:2','item:3'])

tsbApi.db.allDocsQuery(options)

有时候,默认提供的allDocs无法满足业务需求,此时可使用自由度更高的带Query的查询,具体参数作用可参考pdb文档。参数参考open in new window

tsbApi.db.allDocsQuery({
  include_docs: true,
  attachments: true,
  startkey: 'foo',
  endkey: 'foo\ufff0'
})

tsbApi.db.createIndex(index )

这个是使用find方法的前提,需要对需要查找的字段进行索引构建。参数参考open in new window

tsbApi.db.createIndex({
  index: {
    fields: ['type', 'createTime', 'content','searchKey'] //支持同时创建多个
  }
})

tsbApi.db.find(options)

此方法支持比较复杂的查询方式,但是在查询前需要先借助createIndex创建索引。find支持正则表达式,支持排序,支持限制查询数量,建议使用条件优化查询

let dbKey = 'clipboard:item:'
let map: any = {
  _id: {
    $regex: new RegExp(`^${dbKey}`)  //查询clipboard:item:开头的记录,约等于分表
  }
}
if (this.filterType !== 'all') {
  map.type = this.filterType
}
if (this.items.length > 0) {
  map.createTime = {
    $lt: this.items[this.items.length - 1].createTime
  }
}
 let rsFiltered = await tsbApi.db.find({
  selector: map,
  limit:10,
  sort: [
    {
      '_id': 'desc'
    }
  ]
})

复杂find查询条件示例

1.字段为字符串或者数组的时候,匹配=或包含在数组内的条件

查询条件:匹配以dbKey为起始的id,并且 exeName字段为字符串的时候=某个字符串,或者当exeName类型为数组的时候,包含某个字符串

tip: AI 提问描述示例(可供参考):

写一个pouchdb find的查询调节,查询数组型的字段中包含某个字符串元素,或者这个字段是一个字符串的时候,则条件为两者相等,并且id等于指定id

 let map: any = {
        $and: [
          {
            _id: {
              $regex: new RegExp(`^${dbKey}`)
            }
          }
        ] //第一个条件

      }
      if (exeName) {
        map.$and.push({
          $or:
            [{
              exeName: {
                $elemMatch: {
                  $regex: new RegExp(exeName)
                }
              },//数组包含条件,匹配例如 exeName:['a.exe','b.exe']
            },
              {
                exeName: exeName
              }
            ] //匹配exeName:'a.exe'
        }) //增设一个数组包含或者字符串相等的条件
      }