介绍
LokiJS是一个面向文档的javascript数据库,与MongoDB有点类似。
它反对索引,查问和过滤数据汇合。 LokiJS还反对更高级的性能,例如mapReduce,事务,并容许您实现自定义近程同步以将数据保留到服务器(或挪动设施上的本地文件)。
磁盘的持久性曾经在诸如nodejs之类的CommonJS环境中实现,
在挪动设施上,您只须要申请文件系统并将lokijs的serialize()作为内容传递即可。
创立
创立一个 db:
var db = new loki('Example');
除了 Example
这个数据库的名称外, 还能够传递一个选项参数:
interface LokiConfigOptions { adapter: LokiPersistenceAdapter | null; autoload: boolean; autoloadCallback: (err: any) => void; autosave: boolean; autosaveCallback: (err?: any) => void; autosaveInterval: string | number; persistenceMethod: "fs" | "localStorage" | "memory" | null; destructureDelimiter: string; serializationMethod: "normal" | "pretty" | "destructured" | null; throttledSaves: boolean;}
对于参数: persistenceMethod 须要留神的点:
- "fs": 只能在 node 环境中应用(包含 electron)
- "localStorage" : web 中能够应用,并且数据会存在
localStorage
中,进行长久存储 - "memory": 只是简略的存在内容中,如果刷新页面,数据就不存在了
在不同的环境中, 他创立的长久层是不同的, 比方
在浏览器中, 是基于 web 数据库或者 localStorage
(默认) 的
在 node 环境中, 能够基于 fs, 创立文件数据库
对于他们的变动是须要一个 option.adapter
来进行帮助
在 web 中, 如果想要将数据存到 web 数据库中,
那么就须要 option.adapter
了(当传递了 adapter
参数时, 'persistenceMethod' 参数就会被有效)
然而如果应用了 option.adapter
,那么只能应用主动加载数据库和字段保留数据库的计划
减少数据
针对 loki 里的 Collection
如果理解数据库,能够将它当成 表
这种构造
想要增加数据,须要先获取 collection
对象
能够在增加 collection
的时候获取:
const users = db.addCollection('users', {indices: ['email']});
能够间接获取:
const coll = db.getCollection('users')
留神 addCollection
有 2 个参数能够传递:
- 第一个参数是 name 是 collection 的名称
- 第二个是可选项参数,它领有很多参数:
名称 | 类型 | 属性 | 默认值 | 形容 |
---|---|---|---|---|
unique | 数组 | <可选> | [] | 属性名称数组,用于定义惟一束缚 |
exact | 数组 | <可选> | [] | 属性名称数组,用于定义确切的束缚 |
indices | 数组 | <可选> | [] | 用于定义二进制索引的数组属性名称 |
adaptiveBinaryIndices | 布尔值 | <可选> | true | 收集索引将被从新建设而不是懒加载 |
asyncListeners | 布尔值 | <可选> | false | 侦听器是否异步调用 |
disableMeta | 布尔值 | <可选> | false | 设置为true以禁用文档的元属性 |
disableChangesApi | 布尔值 | <可选> | true | 设置为false以启用Changes API |
disableDeltaChangesApi | 布尔值 | <可选> | true | 设置为false以启用Delta更改API(须要更改API,强制克隆) |
autoupdate | 布尔值 | <可选> | false | 应用Object.observe自动更新对象 |
clone | 布尔值 | <可选> | false | 指定是否向用户插入或从用户克隆查问 |
serializableIndices | 布尔值 | <可选> | true[] | 将二进制索引属性上的日期值转换为纪元工夫 |
cloneMethod | 字符串 | <可选> | 'parse-stringify' | 'parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign' |
ttl | int | <可选> | 文件被认为是古老/过期之前的文件工夫(以毫秒为单位)。 | |
ttlInterval | int | <可选> | 革除“古老”文件的工夫距离;默认状况下未设置。 |
应用 inert 增加数据
const coll = db.getCollection('users')var odin = users.insert({name: 'odin', email: 'odin.soap@lokijs.org', age: 38});var thor = users.insert({name: 'thor', email: 'thor.soap@lokijs.org', age: 25});var stan = users.insert({name: 'stan', email: 'stan.soap@lokijs.org', age: 29});// 也能够同时插入多个数据// users.insert([{ name: 'Thor', age: 35}, { name: 'Loki', age: 30}]);
这里要留神的是: 分分明数据的存储状态, 当咱们不应用主动保留和手动保留的时候 insert, 会将数据插入 collection 中, 然而当咱们刷新页面的时候,数据会重置会原来的数据,
如果咱们要将数据全副存下来(即便刷新也会存在的话), 就须要保留:
// var db = new loki('Example'); 这是 db 的由来db.saveDatabase(error => { console.log('保留数据') error && console.log(error)})
获取数据:
获取数据是比拟灵便的,我这里说两种办法:
办法一:
const dv = coll.addDynamicView('test');const results = dv.data();console.log(results)// 这是results打印后果// 0: {name: "odin", email: "odin.soap@lokijs.org", age: 38, meta: {…}, $loki: 1}// 1: {name: "thor", email: "thor.soap@lokijs.org", age: 25, meta: {…}, $loki: 2}// 2: {name: "stan", email: "stan.soap@lokijs.org", age: 29, meta: {…}, $loki: 3}// 3: {name: "oliver", email: "oliver.soap@lokijs.org", age: 31, meta: {…}, $loki: 4}// 4: {name: "hector", email: "hector.soap@lokijs.org", age: 15, meta: {…}, $loki: 5}// 5: {name: "achilles", email: "achilles.soap@lokijs.org", age: 31, meta: {…}, $loki: 6}
办法二:
const resultsLine = coll.chain().data();console.log(resultsLine)// 后果与办法一雷同
获取数据时筛选想要的数据:
办法 1 的筛选:
find
// 通过 coll 间接获取const results4 = coll.find({'age': {'$aeq': 15}});console.log('获取数据 4',results4)// 可应用不同的指令:// 指令名 作用// $eq ===// $ne !==// $aeq ==// $dteq 工夫上的相等// $gt >// $gte >=// $lt <// $lte <=// $between 介于 2 个数之间// 如果不心愿应用二进制索引,并且心愿简略的javascript比拟是能够承受的,咱们提供以下操作,因为它们的简化比拟,它们能够提供更好的执行速度。// $gt -> $jgt// $gte -> $jgte// $lt -> $jlt// $lte -> $jlte// $between -> $jbetween// $regex 应用正则
applyFind
const dv = coll.addDynamicView('test');dv.applyFind({ 'name' : 'odin' });const results = dv.data();
applyWhere
dv2.applyWhere(function(obj) { return obj.name === 'oliver'; });// 作用与上述办法雷同
applySimpleSort
// 依据年龄进行排序const dv3 = coll.addDynamicView('test3');dv3.applySimpleSort("age");const results3 = dv3.data();console.log(results3)
findOne
const results5 = coll.findOne({'age': {'$aeq': 31}});// 获取到的是对象 而不是一个数组console.log('获取数据 5',results5)
findObject
const results6 = coll.findObject({'age': 38});// 应用的后果和 findOne 相似console.log('获取数据 6',results6)
findObjects
const results7 = coll.findObjects({'age': 31});// 返回的是一个数组console.log('获取数据 7',results7)
比拟举荐的是应用 addDynamicView
的形式来筛选,而不是通过 collection
间接获取
须要留神的是 DynamicView
是一个数据格式,他能够 add 能够 get 也能够 remove
办法 2 的筛选:
// 简略的筛选const resultsLine2 = coll.chain().find({ 'name' : 'odin' }).data();// 排序:const resultsLine3 = coll.chain().simplesort('age').data();
当然 chain 里还有其余操作,如: limit, map, findAnd, eqJoin, count等等,
我是更举荐应用第一种办法,这里的几种应用计划我就不具体举例了
还有不倡议应用 chain 的 update,remove 等操作,因为监听器外面会监听不到事件,
这个问题不晓得是成心这么做 还是 bug
批改数据:
update
与 insert 同理:
// 要批改 就须要先获取要批改的货色是什么 const item = coll.findOne({'age': {'$aeq': 31}});item.age = 18coll.update(item);console.log(coll.chain().data())// 打印发现名字为 odin 的年龄曾经改成了 18// 当然想要长久化就得保留数据库:db.saveDatabase(error => { console.log('保留数据') error && console.log(error)})
findAndUpdate
coll.findAndUpdate({'age': {'$aeq': 25}}, data => { // 原名"thor" data.name = 'grewer' return data})// 获取并且批改 集中在同一个办法外面console.log('批改后果 2', coll.chain().data())
updateWhere
coll.updateWhere(data => { return data.name === 'grewer';}, data => { data.age = '999' return data})// 与下面的相似,然而更加自在,而且还能够是用 `{'age': {'$aeq': 15}}` 这种办法来获取
删除数据:
remove
删除数据也是非常简单的(与更新相似):
const item2 = coll.findOne({'age': {'$aeq': 31}});coll.remove(item2);console.log(coll.chain().data())
findAndRemove
coll.findAndRemove({'age': {'$aeq': 15}})// 同 findAndUpdate, 集中了 find 和 removeconsole.log('批改后果 2', coll.chain().data())
removeWhere
// 同 updateWherecoll.removeWhere((value,index)=>{ return index === 1})console.log('删除后果 3', coll.chain().data())
增加操作的监听:
Loki 的 DB 反对自定义事件,应用如下:
// 增加自定义 grewer 事件db.addListener('grewer',(data) => { console.log('grewer事件', data)})// 触发事件db.emit('grewer','qwerty')
Loki 反对对 collection
增加操作的监听, 监听的事件反对以下事件
closedeleteerrorflushbufferinsertpre-insertpre-updateupdatewarning
应用:
coll.on('update', (event) => { console.log('coll change 事件', event)})// inset, delete 等其余事件同理
在咱们应用 update/findAndUpdate/updateWhere
的时候就会主动触发此回调了
对于 Collection transforms
他的官网介绍是这样的:
转换背地的根本思维是容许将后果集“链”过程转换为该过程的对象定义。而后能够抉择命名该数据定义,并将其与汇合一起保留在数据库中。
一个简略的应用:
var tx = [ { type: 'find', value: { 'name': 'oliver' } }];console.log(coll.chain(tx).data())// 打印后果:[{ $loki: 4 age: 18 email: "oliver.soap@lokijs.org" meta: {...} name: "oliver"}]
对于他的应用,感觉像是其余数据库外面的schema
, 我这里也没碰到过具体的状况,所以理解不够粗浅
其余数据库性能:
连表查问:
public eqJoin( joinData: Collection<any> | Resultset<any> | any[], leftJoinProp: string | ((obj: any) => string), rightJoinProp: string | ((obj: any) => string), mapFun?: (left: any, right: any) => any, dataOptions?: Partial<GetDataOptions>): Resultset<any>;
一个简略的应用例子:
// 创立另一个 collection(表)var collection = db.addCollection("test", { unique: ["name"]});collection.insert({owner: 0, name: 'Betsy'});collection.insert({owner: 1, name: 'Bingo'});collection.insert({owner: 2, name: 'Fifi'});collection.insert({owner: 3, name: 'Fuzzy'});collection.insert({owner: 4, name: 'Gizmo'});// 这是另一个表// 进行查问:const resultSet = coll.eqJoin(collection.chain(), 'id', 'owner')// 当 id 和 owner 相等时 数据会被连贯console.log('连表', resultSet.data())// 打印一下 console[{$loki: 1left: {name: "odin", id: 0, email: "odin.soap@lokijs.org", age: 38, meta: {…}, …}meta: {revision: 0, created: 1597421406034, version: 0}right: {owner: 0, name: "Betsy", meta: {…}, $loki: 1}},{$loki: 2left: {name: "grewer", id: 1, email: "thor.soap@lokijs.org", age: "999", meta: {…}, …}meta: {revision: 0, created: 1597421406034, version: 0}right: {owner: 1, name: "Bingo", meta: {…}, $loki: 2}},{$loki: 3left: {name: "stan", email: "stan.soap@lokijs.org", age: 29, meta: {…}, $loki: 3}meta: {revision: 0, created: 1597421406034, version: 0}right: {}},{$loki: 4left: {name: "oliver", email: "oliver.soap@lokijs.org", age: 18, meta: {…}, $loki: 4}meta: {revision: 0, created: 1597421406034, version: 0}right: {}},{$loki: 5left: {name: "hector", email: "hector.soap@lokijs.org", age: 15, meta: {…}, $loki: 5}meta: {revision: 0, created: 1597421406034, version: 0}right: {}},{$loki: 6left: {name: "achilles", email: "achilles.soap@lokijs.org", age: 31}meta: {revision: 0, created: 1597421406034, version: 0}right: {}}]
这就是最简略的连表应用
还有一些没说到的,然而也就是边边角角的货色了,根本就是这些办法的应用
写在最初
Loki 领有 adapter 使得他的适用性特地高,然而绝对具体的应用却比拟少,所以我写了这篇绝对具体一点的文章来记录此数据库的相干操作
对于官网文档地址:
http://techfort.github.io/Lok...
还有这篇文章外面的所有例子的地址:
https://github.com/Grewer/JsD...