介绍
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 = 18
coll.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 和 remove
console.log('修改结果 2', coll.chain().data())
removeWhere
// 同 updateWhere
coll.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 添加操作的监听, 监听的事件支持以下事件
close
delete
error
flushbuffer
insert
pre-insert
pre-update
update
warning
使用:
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 | Resultset | any[],
leftJoinProp: string | ((obj: any) => string),
rightJoinProp: string | ((obj: any) => string),
mapFun?: (left: any, right: any) => any,
dataOptions?: Partial
): Resultset;
一个简单的使用例子:
// 创建另一个 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: 1
left: {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: 2
left: {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: 3
left: {name: "stan", email: "stan.soap@lokijs.org", age: 29, meta: {…}, $loki: 3}
meta: {revision: 0, created: 1597421406034, version: 0}
right: {}
},
{
$loki: 4
left: {name: "oliver", email: "oliver.soap@lokijs.org", age: 18, meta: {…}, $loki: 4}
meta: {revision: 0, created: 1597421406034, version: 0}
right: {}
},
{
$loki: 5
left: {name: "hector", email: "hector.soap@lokijs.org", age: 15, meta: {…}, $loki: 5}
meta: {revision: 0, created: 1597421406034, version: 0}
right: {}
},
{
$loki: 6
left: {name: "achilles", email: "achilles.soap@lokijs.org", age: 31}
meta: {revision: 0, created: 1597421406034, version: 0}
right: {}
}]
这就是最简单的连表使用
还有一些没说到的,但是也就是边边角角的东西了,基本就是这些方法的使用
写在最后
Loki 拥有 adapter 使得他的适用性特别高,但是相对详细的使用却比较少,所以我写了这篇相对详细一点的文章来记录此数据库的相关操作
关于官方文档地址:
还有这篇文章里面的所有例子的地址: