# Schema

如果你希望数据库的结构更严格一点,也可以添加 schema


GoDB 会根据 schema 建立 IndexedDB 数据表,并给相应字段建立索引


import GoDB from 'godb';

// 定义数据库结构
const schema = {
   // user 表:
   user: {
       // user 表的字段:
       name: {
           type: String,
           unique: true // 指定 name 字段在表里唯一
       },
       age: Number
   }
}

const testDB = new GoDB('testDB',  schema );
const user = testDB.table('user');

const data = {
   name: 'luke'
   age: 22
};

user.add(data) // 没问题
 .then(() => user.get({ name: 'luke' })) // 定义schema后,就可以用id以外的字段获取数据
 .then(luke => user.add(luke)) // 报错,name 重复了 


如上面的例子,指定了 schema


  • 定义了 schema,因此 get()delete() 中可以使用 id 以外的字段搜索了,否则只能传入 id
  • 指定了 user.name 这一项是唯一的,因此无法添加重复的 name


当然,你也可以在 table 那定义 schema


const testDB = new GoDB('testDB');
const user = testDB.table('user', {
   name: {
       type: String,
       unique: true
   },
   age: Number
}); 


但这种方式的缺点是,如果定义 table 发生在连接数据库之后,GoDB 会先发起一个 IDBVersionChange 的事件,导致 IndexedDB 数据库版本升级,此时如果有别的 CRUD 操作正在进行,可能会导致建立 table 失败


要避免这个问题倒是很简单,把所有获取 table 的操作紧接在 new GoDB() 之后(保证连接数据库,和连接数据表,是同步而非异步执行的)就可以,这样可以确保所有 table 都在连接完成之前获取到(JS 的事件循环特性)


关于 schema 的设计


部分同学或许会发现,上面定义 schema 的方式有点眼熟,没错,正是参考了 mongoose


  • 定义数据库的字段时,可以只指明数据类型,如上面的 age: Number
  • 也可以使用一个对象,里面除了定义数据类型 type,也指明这个字段是不是唯一的(unique: true),之后会添加更多可选属性,如用来指定字段默认值的 default,和指向别的表的索引 ref


不定义 Schema 时,GoDB 使用起来就像 MongoDB 一样,可以灵活添加数据;区别是 Mongodb 中,每条数据的唯一标识符是 _id,而 GoDBid


虽然这样做的问题是,IndexedDB 毕竟还是存在字段索引这个概念,用户使用不规范的话(如每次添加的数据结构都不一样),久而久之可能会使得数据库的字段比较杂,带来额外的使用成本


定义 Schema 后,GoDB 使用起来就像 MySQL 这种关系型数据库一样,无法往数据表里添加不存在的字段(GoDB 不会阻止这次添加操作,但是会去掉未定义的字段后再添加,同时在浏览器报一个 warning)


因此推荐在项目中,首先定义好 schema,这样不管是维护性上,还是性能上,都要更胜一筹


当然不使用 ​​schema​ 也是完全可行的,使用上也不会有任何问题,是否使用 ​​​schema​ 取决于开发者自己的取舍,如果你的应用不是很复杂,完全可以不用管 ​​schema​,这样使用起来更灵活