#NanoDB Usage (draft)
定位:跨应用,跨平台
##Creating Database
创建数据库,只需要提供库名(此名字用于标识数据库在内存中的名字)和数据源(数据源为空则是一个空数据库)。数据源的来源不关心,只要是完整的JSON数据对象即可。
nano.db('mydb', {
users: [],
books: []
});
##Collection
新建或获取一个数据集(相当于数据表):
var users = mydb.collection('users');
新建一个规定结构(Schema)的数据集:
var books = mydb.collection('books', {
'name': 'book',
'properties': {
'title': {
'type': 'string',
'required': true
}
}
});
例子中新建了books表,要求数据记录必须有一个string类型的必选属性title。增改数据记录时,按这个结构的数据才是有效数据。
##Schema
规范了数据记录的结构,规则: http://tools.ietf.org/html/draft-zyp-json-schema-03
TODO: 提供更详细的规则描述和例子。
##indexes
...
##Inserting
对于未规定结构的数据表,插入一条记录和多条记录:
// insert one record
users.insert({name: 'Neo', age: 24, gender: 'male'}, function (err) {
// result handle
});
// insert multiple records
users.insert([
{name: 'Kar', age: 25, gender: 'male'},
{name: 'Mio', age: 20, gender: 'female'}
], function (err) {
// result handle
});
对于严格规定了数据结构的数据表,插入数据格式必须符合要求,同样支持单条或多条记录:
books.insert({title: 'NanoDB Guide'}, function (err) {
// result handle
});
// malformed
books.insert({name: 'NanoDB Guide'}, function (err) {
// result handle
});
TODO: 多数据插入,部分失败的处理方式(全部回滚 or 只返回失败)。
##Querying
查询条件是以基于对象的查询。
基础查询:
users.find({gender: 'male'}, function (err, rs) {
// result handle
});
高级查询:
// find which the age > 12 && age < 20
users.find({
age: {
$gt: 12,
$lt: 20
}
}, function (err, rs) {
// result handle
});
####Conditional Operators
高级查询支持的所有操作符:
Operator Description
$all all values in the array must be matched
$and &&
$exists exists or not
$gt >
$gte >=
$has has the provided value in an array
$in within a provided array
$is ===
$length matches object's length
$lt <
$lte <=
$ne !=
$nin value not in a provided array
$or ||
$regex regular expression match
$startWith matches a string is start with a given value
$endWith matches a string is end of value
$same matches object same with another
$type matches object where the property is of a given type
TODO:补充或摒弃一些操作符,评估使用频率比较高的;添加更详细的描述和例子。
####基于方法链的查询
跟基于对象的查询的区别是,把操作符函数化。比如:
var youth = users.find('age').gt(12).lt(20);
TODO: 分析可行性。实现上感觉相对比较复杂,回调不好处理。使用起来的话,像一些习惯jq的会容易理解。
##Updating
update操作时,获取所要更新的数据与query的方式相同。update可分两种方式:合并更新和自操作更新。
合并更新,把指定的新值merge到查询出来的数据中:
users.update({name: 'Kar'}, {age: 21}, function (err) {
// ...
});
多结果即等同于批量更新。
自操作更新:
users.update({name: 'Kar'}, function (records) {
records[0].age++;
}, function (err) {
// ...
});
注意:第一个function是查询结果的,发生在查询后,这个时候还没有更新,这个方法正是指定如何更新。
第二个function是更新后的回调。
自操作更新对查询出来的记录所作修改,能直接影响到源数据,能适应更多复杂情况。
books.insert({title: 'Computer Science', category: ['science', 'computer']});
books.update({title: 'Computer Science'}, function (records) {
records[0].category.push('reference');
}, function (err) {
// ...
});
TODO: 接口感觉还是有点奇怪,有些人可能不好理解。
##Deleting
删除动作相对简单,直接删除查询出来的数据:
users.remove({age: {$gt: 12}}, function (err, rs) {
// ...
});
也可以整表删除:
users.remove();
TODO: 为了避免调用remove的时候,误操作没传查询条件,考虑把清除操作由clear方法代替,待定。
##Cursor Methods
Cursor Methods提供对查询结果集(数组)的常用操作的一系列方法,包括排序、过滤、计数等。
因为增删改等操作,都涉及到与数据源同步,大多数同步行为是异步的,而查询只操作内存数据,不涉及异步操作,所以也不一定要使用回调的方式处理查询结果。这样就可以让查询支持方法链形式。
var count = users.find({age: {$gt: 12}}).sort().limit(10).count();
Cursor Methods
Method Description
count() number of objects matching the query specified
filter() filter data from result data
limit(num)
skip(num)
sort(obj) sort by conditions
toArray()
##Reference
Reference用于建立相引用的数据表之间的关系。
// if now users data is [{name: 'Kar', _id:'bmFub2l0ZW1z69556912398376284'}]
books.insert({
title: 'cookbook',
author: {
$ref: 'users#bmFub2l0ZW1z69556912398376284',
}
}, function () {
var cookbook = books.find({title: 'cookbook'});
// result: {title: 'cookbook', author: {name: 'Kar', _id:'bmFub2l0ZW1z69556912398376284'}}
});
当引用的对象数据发生改变时候,所有引用这个对象数据的值也会更新。
$ref 操作符号语法
当前数据库,指定数据表名和id值或查询条件
{$ref: 'collectionName#id'} // reference with collection name and id value
{$ref: 'collectionName?condition=value'} // reference with collection name and condition
{$ref: 'collectionName[index]'} // reference with collection name an index
跨数据库的语法,待定
$dbName.collectionName#id
$dbName.collectionName?condition=value
$ref
的指向结果是唯一的,不必要支持复杂条件的指向,没有太多现实意义。
##Event subscriptions
数据库的所有操作,都会抛出相应的发生前和发生后事件。提供这一机制主要是为了解决,使用不同数据来源(本地存储、服务器端、文件流)的相同操作的行为触发。通过事件监听来实现与核心文件的解耦。
...
##Provider
数据源提供者,如架构图,可以是localStorage,HTTP\REST,甚至是server端的实现。 对于数据源提供者,相应的动作,只要监听数据库操作的事件即可。
// 。。。
##Architecture