跳到主要内容

数据库

基础概念​

Collection​

集合是一系列的文档集,通过 db.collection(name) 可以获取指定集合的引用,在集合上可以进行以下操作

类型接口说明
写add新增文档(触发请求)
计数count获取符合条件的文档条数
读get获取集合中的文档,如果有使用 where 语句定义查询条件,则会返回匹配结果集 (触发请求)
引用doc获取对该集合中指定 id 的文档的引用
查询条件where通过指定条件筛选出匹配的文档,可搭配查询指令(eq, gt, in, ...)使用
skip跳过指定数量的文档,常用于分页,传入 offset
orderBy排序方式
limit返回的结果集(文档数量)的限制,有默认值和上限值(限制最大值是 1000)
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

获取数据库实例​

说明:不需要参数,返回数据库的实例

import cloudbase from "@cloudbase/js-sdk";

const app = cloudbase.init({
env: "xxxx-yyy",
});

const db = app.database();

获取集合的引用​

说明:接受一个 name 参数,指定需引用的集合名称

// 获取 `user` 集合的引用
import cloudbase from "@cloudbase/js-sdk";

const app = cloudbasae.init({
env: "xxxx-yyy",
});

const db = app.database();

const collection = db.collection("user");

查询指令​

eq​

表示字段等于某个值。eq 指令接受一个字面量 (literal),可以是 number, boolean, string, object, array。

比如筛选出所有自己发表的文章,除了用传对象的方式:

const myOpenID = "xxx";
db.collection("articles").where({
_openid: myOpenID,
});

还可以用指令:

const _ = db.command;
const myOpenID = "xxx";
db.collection("articles").where({
_openid: _.eq(openid),
});

注意 eq 指令比对象的方式有更大的灵活性,可以用于表示字段等于某个对象的情况,比如:

// 这种写法表示匹配 stat.publishYear == 2018 且 stat.language == 'zh-CN'
db.collection("articles").where({
stat: {
publishYear: 2018,
language: "zh-CN",
},
});
// 这种写法表示 stat 对象等于 { publishYear: 2018, language: 'zh-CN' }
const _ = db.command;
db.collection("articles").where({
stat: _.eq({
publishYear: 2018,
language: "zh-CN",
}),
});

neq​

字段不等于。neq 指令接受一个字面量 (literal),可以是 number, boolean, string, object, array。

如筛选出品牌不为 X 的计算机:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
brand: _.neq("X"),
},
});

gt​

字段大于指定值。

如筛选出价格大于 2000 的计算机:

const _ = db.command;
db.collection("goods").where({
category: "computer",
price: _.gt(2000),
});

gte​

字段大于或等于指定值。

lt​

字段小于指定值。

lte​

字段小于或等于指定值。

in​

字段值在给定的数组中。

筛选出内存为 8g 或 16g 的计算机商品:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.in([8, 16]),
},
});

nin​

字段值不在给定的数组中。

筛选出内存不是 8g 或 16g 的计算机商品:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.nin([8, 16]),
},
});

and​

表示需同时满足指定的两个或以上的条件。

如筛选出内存大于 4g 小于 32g 的计算机商品:

流式写法:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.gt(4).and(_.lt(32)),
},
});

前置写法:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.and(_.gt(4), _.lt(32)),
},
});

or​

表示需满足所有指定条件中的至少一个。如筛选出价格小于 4000 或在 6000-8000 之间的计算机:

流式写法:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
price: _.lt(4000).or(_.gt(6000).and(_.lt(8000))),
},
});

前置写法:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
price: _.or(_.lt(4000), _.and(_.gt(6000), _.lt(8000))),
},
});

如果要跨字段 “或” 操作:(如筛选出内存 8g 或 cpu 3.2 ghz 的计算机)

const _ = db.command;
db.collection("goods").where(
_.or(
{
type: {
memory: _.gt(8),
},
},
{
type: {
cpu: 3.2,
},
}
)
);

RegExp​

根据正则表达式进行筛选

例如下面可以筛选出 version 字段开头是 "数字+s" 的文档,并且忽略大小写:

// 可以直接使用正则表达式
db.collection('articles').where({
version: /^\ds/i
})

// 或者
db.collection('articles').where({
version: new db.RegExp({
regexp: '^\\ds' // 正则表达式为 /^\ds/,转义后变成 '^\\ds'
options: 'i' // i表示忽略大小写
})
})

更新指令​

set​

描述:用于设定字段等于指定值。这种方法相比传入纯 JS 对象的好处是能够指定字段等于一个对象。

示例代码:

// 以下方法只会更新 style.color 为 red,而不是将 style 更新为 { color: 'red' },即不影响 style 中的其他字段
db.collection("todos")
.doc("doc-id")
.update({
style: {
color: "red",
},
});

// 以下方法更新 style 为 { color: 'red', size: 'large' }
const _ = db.command;
db.collection("todos")
.doc("doc-id")
.update({
style: _.set({
color: "red",
size: "large",
}),
});

inc​

描述:用于指示字段自增某个值,这是个原子操作,使用这个操作指令而不是先读数据、再加、再写回的好处是:

备注:

  1. 原子性:多个用户同时写,对数据库来说都是将字段加一,不会有后来者覆写前者的情况
  2. 减少一次网络请求:不需先读再写

之后的 mul 指令同理。

示例代码:

const _ = db.command;

db.collection("user")
.where({
_openid: "my-open-id",
})
.update({
count: {
favorites: _.inc(1),
},
})
.then(function (res) {});

mul​

描述:用于指示字段自乘某个值。

remove​

更新指令。用于表示删除某个字段。如某人删除了自己一条商品评价中的评分:

const _ = db.command;

db.collection("comments")
.doc("comment-id")
.update({
rating: _.remove(),
})
.then(function (res) {});

push​

向数组尾部追加元素,支持传入单个元素或数组

const _ = db.command;

db.collection("comments")
.doc("comment-id")
.update({
// users: _.push('aaa')
users: _.push(["aaa", "bbb"]),
})
.then(function (res) {});

pop​

删除数组尾部元素

const _ = db.command;

db.collection("comments")
.doc("comment-id")
.update({
users: _.pop(),
})
.then(function (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 的计算机商品:

const _ = db.command; // 取指令
db.collection("goods").where({
category: "computer",
type: {
memory: _.gt(8), // 表示大于 8
},
});

limit​

描述:指定查询结果集数量上限

输入参数:

参数类型必填说明
-Integer是限制展示的数值(限制最大值是 1000)

使用示例

collection
.limit(1)
.get()
.then(function (res) {});

skip​

描述:指定查询返回结果时从指定索引之后的结果开始返回,常用于分页 输入参数:

参数类型必填说明
-Integer是跳过的条目数量

示例代码

collection
.skip(4)
.get()
.then(function (res) {});

field​

描述:指定返回结果中文档需返回的字段

输入参数:

参数类型必填说明
-object是要过滤的字段,不返回传 false,返回传 true

示例代码

collection.field({ age: true });

备注:field 方法接受一个必填对象用于指定需返回的字段,对象的各个 key 表示要返回或不要返回的字段,value 传入 true|false(或 1|-1)表示要返回还是不要返回。

orderBy​

描述:指定查询排序条件

输入参数:

参数类型必填说明
fieldstring是排序的字段
orderTypestring是排序的顺序,升序(asc) 或 降序(desc)

备注:方法接受一个必填字符串参数 fieldName 用于定义需要排序的字段,一个字符串参数 order 定义排序顺序。order 只能取 asc 或 desc。

如果需要对嵌套字段排序,需要用 "点表示法" 连接嵌套字段,比如 style.color 表示字段 style 里的嵌套字段 color。

同时也支持按多个字段排序,多次调用 orderBy 即可,多字段排序时的顺序会按照 orderBy 调用顺序先后对多个字段排序

示例代码

collection
.orderBy("name", "asc")
.get()
.then(function (res) {});

add​

1. 接口描述​

接口功能:插入一条文档

接口声明:collection.add(object: Object): Promise<Object>

备注:set 方法也可以用来新增文档,请参看文档更新部分 set 方法

示例:

2. 输入参数​

参数类型必填说明
dataobject是{\_id: '10001', 'name': 'Ben'} _id 非必填

3. 输出参数​

字段类型必填说明
codestring否状态码,操作成功则不返回
messagestring否错误描述

4. 示例代码​

collection
.add({
name: "Ben",
})
.then((res) => {})
.catch((e) => {});

get​

1. 接口描述​

接口功能:获取数据库查询结果

接口声明:get(): Promise<Object>

注:get()如不指定 limit 则默认取前 100 条数据,且最大取前 100 条数据。

2. 输入参数​

空

3. 输出参数​

字段类型必填说明
codestring否状态码,操作成功则不返回
messagestring否错误描述
dataobject否查询结果
requestIdstring是请求序列号,用于错误排查

4. 示例代码​

collection
.where({
category: "computer",
type: {
memory: 8,
},
})
.get()
.then((res) => {})
.catch((e) => {});

count​

1. 接口描述​

接口功能:获取数据库查询结果的数目

接口声明:cout(): Promise<Object>

2. 输入参数​

空

3. 输出参数​

字段类型必填说明
codestring否状态码,操作成功则不返回
messagestring否错误描述
totalInteger否计数结果
requestIdstring否请求序列号,用于错误排查

4. 示例代码​

db.collection("goods")
.where({
category: "computer",
type: {
memory: 8,
},
})
.count()
.then(function (res) {
const total = res.total; //符合条件的文档的数量
});

remove​

1. 接口描述​

接口功能:删除一条文档

接口声明:remove(): Promise<Object>

2. 输入参数​

无

3. 输出参数​

字段类型必填说明
codestring否状态码,操作成功则不返回
messagestring否错误描述
deletedInteter否删除的文档数量
requestIdstring是请求序列号,用于错误排查

4. 示例代码​

方式 1:通过  指定文档 ID 删除

collection.doc(_id).remove()

collection
.doc("xxx")
.remove()
.then((res) => {
console.log(`${res.deleted} docs deleted`);
})
.catch((e) => {});

方式 2:条件查找文档然后直接批量删除

// 删除字段a的值大于2的文档
collection
.where({
a: _.gt(2),
})
.remove()
.then(function (res) {
const deleted = res.deleted;
});

update / set​

1. 接口描述​

接口功能:更新文档

接口声明:

update(object: <Object\>): Promise<Object>

set(object: <Object\>): Promise<Object>

备注:update 和 set 都可以用来更新文档,区别是 set 方法在要更新的文档不存在时新增一个文档;而 update 方法什么也不会做,返回 updated 为 0

2. 输入参数​

字段类型必填说明
-<Object>是替换文档的定义

3. 输出参数​

字段类型必填说明
codestring否状态码,操作成功则不返回
messagestring否错误描述
updatedInteger否影响的文档数量
upsertedIdstring否插入的文档的 id
requestIdstring是请求序列号,用于错误排查

4. 示例代码​

更新指定文档

//更新指定文档
collection
.doc("doc-id")
.update({
name: "Hey",
})
.then(function (res) {});

更新文档,如果不存在则创建

//更新单个文档
collection
.doc("doc-id")
.set({
name: "Hey",
})
.then(function (res) {});

//批量更新文档
collection
.where({ name: _.eq("hey") })
.update({
age: 18,
})
.then(function (res) {});

GEO 地理位置​

注意:如果需要对类型为地理位置的字段进行搜索,一定要建立地理位置索引。

GEO 数据类型​

Point​

用于表示地理位置点,用经纬度唯一标记一个点,这是一个特殊的数据存储类型。

签名:Point(longitude: number, latitude: number)

示例:

new db.Geo.Point(longitude, latitude);

LineString​

用于表示地理路径,是由两个或者更多的 Point 组成的线段。

签名:LineString(points: Point[])

示例:

new db.Geo.LineString([
new db.Geo.Point(lngA, latA),
new db.Geo.Point(lngB, latB),
// ...
]);

Polygon​

用于表示地理上的一个多边形(有洞或无洞均可),它是由一个或多个闭环 LineString 组成的几何图形。

由一个环组成的 Polygon 是没有洞的多边形,由多个环组成的是有洞的多边形。对由多个环(LineString)组成的多边形(Polygon),第一个环是外环,所有其他环是内环(洞)。

签名:Polygon(lines: LineString[])

示例:

new db.Geo.Polygon([
new db.Geo.LineString(...),
new db.Geo.LineString(...),
// ...
])

MultiPoint​

用于表示多个点 Point 的集合。

签名:MultiPoint(points: Point[])

示例:

new db.Geo.MultiPoint([
new db.Geo.Point(lngA, latA),
new db.Geo.Point(lngB, latB),
// ...
]);

MultiLineString​

用于表示多个地理路径 LineString 的集合。

签名:MultiLineString(lines: LineString[])

示例:

new db.Geo.MultiLineString([
new db.Geo.LineString(...),
new db.Geo.LineString(...),
// ...
])

MultiPolygon​

用于表示多个地理多边形 Polygon 的集合。

签名:MultiPolygon(polygons: Polygon[])

示例:

new db.Geo.MultiPolygon([
new db.Geo.Polygon(...),
new db.Geo.Polygon(...),
// ...
])

GEO 操作符​

geoNear​

按从近到远的顺序,找出字段值在给定点的附近的文档。

签名:

db.command.geoNear(options: IOptions)

interface IOptions {
geometry: Point // 点的地理位置
maxDistance?: number // 选填,最大距离,米为单位
minDistance?: number // 选填,最小距离,米为单位
}

// 注意:geoNear 仅支持 geometry、maxDistance、minDistance 三个参数,不支持通过参数限制返回条数(例如 limit: 10)
// 如需限制返回条数,请在 where() 之后链式调用 limit(),例如 .where({ location: _.geoNear({ ... }) }).limit(10).get()

示例:

db.collection("user").where({
location: db.command.geoNear({
geometry: new db.Geo.Point(lngA, latA),
maxDistance: 1000,
minDistance: 0,
}),
});

geoWithin​

找出字段值在指定 Polygon / MultiPolygon 内的文档,无排序

签名:

db.command.geoWithin(IOptions);

interface IOptions {
geometry: Polygon | MultiPolygon; // 地理位置
}

示例:

// 一个闭合的区域
const 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({
geometry: area,
}),
});

geoIntersects​

找出字段值和给定的地理位置图形相交的文档

签名:

db.command.geoIntersects(IOptions);

interface IOptions {
geometry:
| Point
| LineString
| MultiPoint
| MultiLineString
| Polygon
| MultiPolygon; // 地理位置
}

示例:

// 一条路径
const line = new LineString([new Point(lngA, latA), new Point(lngB, latB)]);

// 搜索 location 与这条路径相交的 user
db.collection("user").where({
location: db.command.geoIntersects({
geometry: line,
}),
});

数据库实时推送​

监听指定集合中符合查询条件的文档,通过 onchange 回调获得文档的变化详情 (where 参数为查询条件 参考 查询文档)

import cloudbase from "@cloudbase/js-sdk";

const app = cloudbase.init({
env: "tcbenv-mPIgjhnq",
});
const db = app.database();
const _ = db.command;
const collection = db.collection("collName"); // collName 需填当前env下集合名称

let ref = collection.where({ test: _.gt(0) }).watch({
onChange: (snapshot) => {
console.log("收到snapshot**********", snapshot);
},
onError: (error) => {
console.log("收到error**********", error);
},
});

单个 doc 的监听,也可以采用 doc('docId').watch()形式

let ref = collection.doc("one docId").watch({
onChange: (snapshot) => {
console.log("收到snapshot**********", snapshot);
},
onError: (error) => {
console.log("收到error**********", error);
},
});

手动关闭监听,当前监听将不再收到推送

ref.close().then((result) => {
// 监听被关闭
});