cloudbase_database 0.0.3 cloudbase_database: ^0.0.3 copied to clipboard
Flutter plugin for cloudbase database.
cloudbase_database #
cloudbase_database
为 CloudBase Flutter SDK plugin 之一,提供了在 Flutter 项目中调用 CloudBase 文档型数据库的能力。
基础概念 #
Collection #
集合是一系列的文档集,通过 db.collection(name)
可以获取指定集合的引用,在集合上可以进行以下操作
类型 | 接口 | 说明 |
---|---|---|
写 | add | 新增文档(触发请求) |
计数 | count | 获取复合条件的文档条数 |
读 | get | 获取集合中的文档,如果有使用 where 语句定义查询条件,则会返回匹配结果集 (触发请求) |
引用 | doc | 获取对该集合中指定 id 的文档的引用 |
查询条件 | where | 通过指定条件筛选出匹配的文档,可搭配查询指令(eq, gt, in, ...)使用 |
skip | 跳过指定数量的文档,常用于分页,传入 offset | |
orderBy | 排序方式 | |
limit | 返回的结果集(文档数量)的限制,有默认值和上限值 | |
field | 指定需要返回的字段 |
查询及更新指令用于在 where
中指定字段需满足的条件,指令可通过 db.command
对象取得。
Record / Document #
文档是数据库集合中的一个存储单元,在云开发里是一个json对象。通过 db.collection(collectionName).doc(docId)
可以获取指定集合上指定 id 的文档的引用,在文档上可以进行以下操作
接口 | 说明 |
---|---|
写 | set |
update | |
remove | |
读 | get |
Query Command #
查询指令,应用于构建查询条件。以下指令皆挂载在 db.command
下
类型 | 接口 | 说明 |
---|---|---|
比较运算 | eq | 字段 == |
neq | 字段 != | |
gt | 字段 > | |
gte | 字段 >= | |
lt | 字段 < | |
lte | 字段 <= | |
in | 字段值在数组里 | |
nin | 字段值不在数组里 | |
逻辑运算 | and | 表示需同时满足指定的所有条件 |
or | 表示需同时满足指定条件中的至少一个 |
Update Command #
更新指令,应用于构建更新操作。以下指令皆挂载在 db.command
下
类型 | 接口 | 说明 |
---|---|---|
更新指令 | set | 设定字段等于指定值 |
inc | 指示字段自增某个值 | |
mul | 指示字段自乘某个值 | |
remove | 删除某个字段 | |
push | 向数组尾部追加元素,支持传入单个元素或数组 | |
pop | 删除数组尾部元素 | |
shift | 删除数组头部元素。使用同pop | |
unshift | 向数组头部添加元素,支持传入单个元素或数组。使用同push |
获取数据库实例 #
说明:传入 CloudBaseCore 实例,返回数据库的实例
import 'package:cloudbase_core/cloudbase_core.dart';
import 'package:cloudbase_database/cloudbase_database.dart';
void main() async {
CloudBaseCore core = CloudBaseCore.init({'env': 'your-env-id'});
CloudBaseDatabase db = CloudBaseDatabase(core);
}
获取集合的引用 #
说明:接受一个 name 参数,指定需引用的集合名称
// 获取 `user` 集合的引用
import 'package:cloudbase_core/cloudbase_core.dart';
import 'package:cloudbase_database/cloudbase_database.dart';
void main() async {
CloudBaseCore core = CloudBaseCore.init({'env': 'your-env-id'});
CloudBaseDatabase db = CloudBaseDatabase(core);
Collection collection = db.collection('user');
}
查询指令 #
eq #
表示字段等于某个值。eq
指令接受一个字面量 (literal),可以是 num
, bool
, String
, Map
, List
。
比如筛选出所有自己发表的文章,除了用传对象的方式:
var myOpenID = 'xxx';
db.collection('articles').where({
'_openid': myOpenID
});
还可以用指令:
var _ = db.command;
var myOpenID = 'xxx';
db.collection('articles').where({
'_openid': _.eq(myOpenID)
});
注意 eq
指令比对象的方式有更大的灵活性,可以用于表示字段等于某个对象的情况,比如:
// 这种写法表示匹配 stat['publishYear'] == 2018 且 stat['language'] == 'zh-CN'
db.collection('articles').where({
'stat': {
'publishYear': 2018,
'language': 'zh-CN'
}
})
// 这种写法表示 stat == { 'publishYear': 2018, 'language': 'zh-CN' }
var _ = db.command
db.collection('articles').where({
'stat': _.eq({
'publishYear': 2018,
'language': 'zh-CN'
})
})
neq #
字段不等于。neq
指令接受一个字面量 (literal),可以是 num
, bool
, String
, Map
, List
。
如筛选出品牌不为 X 的计算机:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'brand': _.neq('X')
}
});
gt #
字段大于指定值。
如筛选出价格大于 2000 的计算机:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'price': _.gt(2000)
});
gte #
字段大于或等于指定值。
lt #
字段小于指定值。
lte #
字段小于或等于指定值。
into #
字段值在给定的数组中。
筛选出内存为 8g 或 16g 的计算机商品:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': _.into([8, 16])
}
});
nin #
字段值不在给定的数组中。
筛选出内存不是 8g 或 16g 的计算机商品:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': _.nin([8, 16])
}
});
and #
表示需同时满足指定的两个或以上的条件。
如筛选出内存大于 4g 小于 32g 的计算机商品:
流式写法:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': _.gt(4).and(_.lt(32))
}
});
前置写法:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': _.and([_.gt(4), _.lt(32)])
}
});
or #
表示需满足所有指定条件中的至少一个。如筛选出价格小于 4000 或在 6000-8000 之间的计算机:
流式写法:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'price': _.lt(4000).or(_.gt(6000).and(_.lt(8000)))
}
});
前置写法:
var _ = db.command;
db.collection('goods').where({
'category': 'computer',
'type': {
'price': _.or([_.lt(4000), _.and([_.gt(6000), _.lt(8000)])])
}
});
如果要跨字段 “或” 操作:(如筛选出内存 8g 或 cpu 3.2 ghz 的计算机)
var _ = db.command;
db.collection('goods').where(_.or([
{
'type': {
'memory': _.gt(8)
}
},
{
'type': {
'cpu': 3.2
}
}
]));
RegExp #
根据正则表达式进行筛选
例如下面可以筛选出 version
字段开头是 "数字+s" 的文档,并且忽略大小写:
db.collection('articles').where({
version: db.regExp(
'^\\ds', // 正则表达式/^\ds/,转义后变成 '^\\ds'
'i' // options, i表示忽略大小写
)
});
更新指令 #
set #
描述:用于设定字段等于指定值。
示例代码:
// 以下方法只会更新 property['location'] 和 property['size'],如果 property 对象中有
db.collection('photo').doc('doc-id').update({
'data': {
'property': {
'location': 'guangzhou',
'size': 8
}
}
}).then((res) {
});
inc #
描述:用于指示字段自增某个值,这是个原子操作,使用这个操作指令而不是先读数据、再加、再写回的好处是:
- 原子性:多个用户同时写,对数据库来说都是将字段加一,不会有后来者覆写前者的情况
- 减少一次网络请求:不需先读再写
之后的 mul 指令同理。
示例代码:
var _ = db.command;
db.collection('user').where({
'_openid': 'my-open-id'
}).update({
'count': {
'favorites': _.inc(1)
}
}).then((res) {
});
mul #
描述:用于指示字段自乘某个值。
remove #
更新指令。用于表示删除某个字段。如某人删除了自己一条商品评价中的评分:
var _ = db.command;
db.collection('comments').doc('comment-id').update({
'rating': _.remove()
}).then((res) {
});
push #
向数组尾部追加元素,支持传入单个元素或数组
var _ = db.command;
db.collection('comments').doc('comment-id').update({
// 'users': _.push('aaa')
'users': _.push(['aaa', 'bbb'])
}).then((res) {
});
pop #
删除数组尾部元素
var _ = db.command;
db.collection('comments').doc('comment-id').update({
'users': _.pop()
}).then((res) {
});
unshift #
向数组头部添加元素,支持传入单个元素或数组。使用同push
shift #
删除数组头部元素。使用同pop
构建查询条件 #
支持 where()
、limit()
、skip()
、orderBy()
、get()
、update()
、field()
、count()
等操作。
只有当调用get()
、 update()
时才会真正发送请求。
where #
描述:设置过滤条件。where 可接收对象作为参数,表示筛选出拥有和传入对象相同的 key-value 的文档。
输入参数: 无
比如筛选出所有类型为计算机的、内存为 8g 的商品:
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': 8,
}
});
如果要表达更复杂的查询,可使用高级查询指令,比如筛选出所有内存大于 8g 的计算机商品:
var _ = db.command // 取指令
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': _.gt(8), // 表示大于 8
}
})
limit #
描述:指定查询结果集数量上限
输入参数:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
- | int | 是 | 限制展示的数值 |
使用示例
collection.limit(1).get().then((res) {
});
skip #
描述:指定查询返回结果时从指定序列后的结果开始返回,常用于分页 输入参数:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
- | int | 是 | 限制展示的数值 |
示例代码
collection.skip(4).get().then((res) {
});
field #
描述:指定返回结果中文档需返回的字段
输入参数:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
projection | Map<String, bool> | 是 | 要过滤的字段,不返回传false,返回传true |
示例代码
collection.field({ 'age': true }).get().then((res) {
});
备注:field方法接受一个必填对象用于指定需返回的字段,对象的各个 key 表示要返回或不要返回的字段,value 传入 true|false 表示要返回还是不要返回。
orderBy #
描述:指定查询排序条件
输入参数:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
field | String | 是 | 排序的字段 |
orderType | String | 是 | 排序的顺序,升序(asc) 或 降序(desc) |
备注:方法接受一个必填字符串参数 fieldName 用于定义需要排序的字段,一个字符串参数 order 定义排序顺序。order 只能取 asc 或 desc。
同时也支持按多个字段排序,多次调用 orderBy 即可,多字段排序时的顺序会按照 orderBy 调用顺序先后对多个字段排序
示例代码
collection.orderBy("name", "asc").get().then((res) {
});
add #
1. 接口描述
接口功能:插入一条文档
接口声明:Future<DbCreateResponse> collection.add(dynamic data) async {}
备注:set方法也可以用来新增文档,请参看文档更新部分set方法
示例:
2. 输入参数
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
data | dynamic | 是 | {'_id': '10001', 'name': 'Ben'} _id 非必填 |
3. 输出参数
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
code | String | 否 | 状态码,操作成功则不返回 |
message | String | 否 | 错误描述 |
4. 示例代码
collection.add({
'name': 'Ben'
}).then((res) {
}).catchError((e) {
});
get #
1. 接口描述
接口功能:获取数据库查询结果
接口声明:Future<DbQueryResponse> get() async {}
注:get()如不指定limit则默认取前100条数据,且最大取前100条数据。
2. 输入参数
空
3. 输出参数
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
code | String | 否 | 状态码,操作成功则不返回 |
message | String | 否 | 错误描述 |
data | dynamic | 否 | 查询结果 |
requestId | String | 是 | 请求序列号,用于错误排查 |
4. 示例代码
collection.where({
'category': 'computer',
'type': {
'memory': 8,
}
}).get().then((res) {
var data = res.data;
}).catchError((e) => {
});
count #
1. 接口描述
接口功能:获取数据库查询结果
接口声明:Future<DbQueryResponse> count() async {}
2. 输入参数
空
3. 输出参数
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
code | String | 否 | 状态码,操作成功则不返回 |
message | String | 否 | 错误描述 |
total | int | 否 | 计数结果 |
requestId | String | 否 | 请求序列号,用于错误排查 |
4. 示例代码
db.collection('goods').where({
'category': 'computer',
'type': {
'memory': 8,
}
}).count().then((res) {
var total = res.total; //符合条件的文档的数量
})
remove #
1. 接口描述
接口功能:删除一条文档
接口声明:Future<DbRemoveResponse> remove() async {}
2. 输入参数
无
3. 输出参数
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
code | String | 否 | 状态码,操作成功则不返回 |
message | String | 否 | 错误描述 |
deleted | int | 否 | 删除的文档数量 |
requestId | String | 是 | 请求序列号,用于错误排查 |
4. 示例代码
方式1:通过指定文档ID删除
collection.doc('xxx').remove()
.then((res) {
var deleted = res.deleted;
})
.catchError((e) {
});
方式2:条件查找文档然后直接批量删除
// 删除字段a的值大于2的文档
collection.where({
'a': _.gt(2)
}).remove().then((res) {
var deleted = res.deleted;
})
update / set #
1. 接口描述
接口功能:更新文档
接口声明:
Future<DbUpdateResponse> update(dynamic data) async {}
Future<DbUpdateResponse> set(dynamic data) async {}
备注:update和set都可以用来更新文档,区别是set方法在要更新的文档不存在时新增一个文档;而update方法什么也不会做,返回updateed为0
2. 输入参数
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
data | dynamic | 是 | 替换文档的定义 |
3. 输出参数
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
code | String | 否 | 状态码,操作成功则不返回 |
message | String | 否 | 错误描述 |
updated | int | 否 | 影响的文档数量 |
upsertedId | String | 否 | 插入的文档的id |
requestId | String | 是 | 请求序列号,用于错误排查 |
4. 示例代码
更新指定文档
//更新指定文档
collection.doc('doc-id').update({
'name': "Hey"
}).then((res) {
});
更新文档,如果不存在则创建
//更新单个文档
collection.doc('doc-id').set({
'name': "Hey"
}).then((res) {
});
//批量更新文档
collection.where({'name': _.eq('hey')}).update({
'age': 18,
}).then((res) {
});
GEO地理位置 #
注意:如果需要对类型为地理位置的字段进行搜索,一定要建立地理位置索引。
GEO数据类型 #
Point
用于表示地理位置点,用经纬度唯一标记一个点,这是一个特殊的数据存储类型。
签名:Point(num longitude, num latitude)
示例:
var ponit = new Point(longitude, latitude);
LineString
用于表示地理路径,是由两个或者更多的 Point
组成的线段。
签名:LineString(List<Point> points)
示例:
var line = new LineString([
new Point(lngA, latA),
new Point(lngB, latB),
// ...
]);
Polygon
用于表示地理上的一个多边形(有洞或无洞均可),它是由一个或多个闭环 LineString
组成的几何图形。
由一个环组成的 Polygon
是没有洞的多边形,由多个环组成的是有洞的多边形。对由多个环(LineString
)组成的多边形(Polygon
),第一个环是外环,所有其他环是内环(洞)。
签名:Polygon(List<LineString> lines)
示例:
var polygon = new Polygon([
new LineString(...),
new LineString(...),
// ...
]);
MultiPoint
用于表示多个点 Point
的集合。
签名:MultiPoint(List<Point> points)
示例:
var points = new MultiPoint([
new Point(lngA, latA),
new Point(lngB, latB),
// ...
]);
MultiLineString
用于表示多个地理路径 LineString
的集合。
签名:MultiLineString(List<LineString> lines)
示例:
var lines = new MultiLineString([
new LineString(...),
new LineString(...),
// ...
]);
MultiPolygon
用于表示多个地理多边形 Polygon
的集合。
签名:MultiPolygon(List<Polygon> polygons)
示例:
var polygons = new MultiPolygon([
new Polygon(...),
new Polygon(...),
// ...
]);
GEO操作符 #
geoNear
按从近到远的顺序,找出字段值在给定点的附近的文档。
示例:
db.collection('user').where({
'location': db.command.geoNear(
new Point(lngA, latA),
maxDistance: 1000,
minDistance: 0
)
});
geoWithin
找出字段值在指定 Polygon / MultiPolygon 内的文档,无排序
示例:
// 一个闭合的区域
var area = new Polygon([
new LineString([
new Point(lngA, latA),
new Point(lngB, latB),
new Point(lngC, latC),
new Point(lngA, latA)
]),
]);
// 搜索 location 字段在这个区域中的 user
db.collection('user').where({
'location': db.command.geoWithin(area)
});
geoIntersects
找出字段值和给定的地理位置图形相交的文档
示例:
// 一条路径
var line = new LineString([
new Point(lngA, latA),
new Point(lngB, latB)
]);
// 搜索 location 与这条路径相交的 user
db.collection('user').where({
'location': db.command.geoIntersects(line)
});