diff --git a/docs/uniCloud/authentication.md b/docs/uniCloud/authentication.md
index fed8705453a52c0a5c00a438d763f8d92288734f..d923c5849c3a5bd7089cf2db437cd4d46e57a025 100644
--- a/docs/uniCloud/authentication.md
+++ b/docs/uniCloud/authentication.md
@@ -1,6 +1,12 @@
**本章内容仅针对腾讯云开发,阿里侧暂不支持**
-**腾讯云侧必须以任意登录方式登录之后才可以访问云端资源。开发者在控制台开启匿名登录之后,可以在客户端调用匿名登录来获取访问云端资源的权限**
+默认情况下所有用户都是通过匿名登录访问云函数以及云存储的,自定义登录提供了在云端区分用户身份的能力。比如云存储权限配置为仅创建者可写时,文件上传者的userId和当前用户的userId一致时才可以覆盖该文件。
+
+## 名词解释
+
+- Ticket(票据):由云函数调用`createTicket`返回的票据,用于客户端使用票据进行登录操作
+- 匿名登录:用户未进行登录操作的状态
+- 短期访问令牌:用户身份的凭证(access token),调用`signInWithTicket`或者`linkAndRetrieveDataWithTicket`之后会自动进行存储
## uniCloud.auth()
@@ -12,7 +18,7 @@
const auth = uniCloud.auth()
```
-## auth.signInAnonymously()
+
-## auth.signInWithTicket()
+## auth.signInWithTicket()@signinwithticket
-进行自定义登录,详细描述参考[自定义登录](#自定义登录)
+使用,详细描述参考[登录流程](#cloudtoken)
**示例代码**
@@ -64,7 +70,7 @@ auth.getLoginState().then(loginState => {
|字段 |类型 |是否必备 |说明 |
|:-: |:-: |:-: |:-: |
|uid |string |是 |用户在云开发的唯一ID |
-
+|customUserId |string |否 |用户使用自定义登录传入的用户Id |
**示例代码**
@@ -78,24 +84,28 @@ auth.signInWithTicket('YourTicket').then(() => {
})
```
-## 自定义登录
+## 登录流程@cloudtoken
+
+`uniCloud`允许开发者使用特定的登录凭据`Ticket`对用户进行身份认证。开发者可以使用`服务端 SDK`来创建`Ticket`,并且将`Ticket`传入到应用内,然后调用`signInWithTicket()`获得登录态。
-`uniCloud`允许开发者使用特定的登录凭据`Ticket`对用户进行身份认证。开发者可以使用`服务端 SDK`来创建`Ticket`,并且将`token`传入到应用内,然后调用`signInWithTicket()`获得登录态。
+### 第一步:获取私钥文件
-### 获取私钥文件
+登录uniCloud控制台[uniCloud控制台](http://unicloud.dcloud.net.cn/),在`自定义登录`中,点击“生成并下载”
-登录uniCloud控制台[uniCloud控制台](http://unicloud.dcloud.net.cn/),在`用户管理页面`中,点击“登录设置”,然后**生成并下载私钥**:
+**注意:重复生成私钥会使之前生成的私钥失效,并导致用户登录状态失效**
-![uniCloud下载私钥](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uniCloud/auth-custom.png)
+![uniCloud下载私钥](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uniCloud/cloud-token-web.png)
-### 使用云函数创建登录凭据
+### 第二步:使用云函数创建登录凭据
-获取私钥文件之后,重命名为`credentials.json`放在云函数同级目录即可
+获取私钥文件(`credentials.json`)之后,放在需要生成`Ticket`的云函数内`index.js`同级即可
-`服务端 SDK`内置了生成`Ticket`的接口,开发者需要提供一个自定义的`customUserId`作为用户的唯一身份标识。`Ticket`有效期为**5分钟**,过期则失效。
+`服务端 SDK`内置了生成`Ticket`的接口,开发者需要提供一个自定义的`customUserId`作为用户的**唯一身份标识**。`Ticket`有效期为**5分钟**,过期则失效。
每个用户的`customUserId`不能相同,每次用户重新登录时,原有的登录态将会失效。
+**Ticket一般在验证了用户名密码成功之后下发**
+
```js
let customUserId = '123456';
@@ -105,34 +115,7 @@ const ticket = uniCloud.auth().createTicket(customUserId, {
// 然后把 ticket 发送给客户端
```
-
-
-### 客户端上使用Ticket登录
+### 第三步:客户端上使用Ticket登录
创建`Ticket`之后,开发者应将`Ticket`发送至客户端,然后使用`客户端SDK`提供的 `signInWithTicket()` 登录`uniCloud`:
@@ -146,28 +129,13 @@ auth.signInWithTicket(ticket).then(() => {
## 匿名登录
uniCloud允许开发者使用匿名登录的方式进行静默授权,可以避免强制登录。在匿名状态下可正常的调用uniCloud的资源,开发者同时可以配合安全规则针对匿名用户制定对应的访问限制。
-### 开启匿名登录授权
-登录uniCloud控制台[uniCloud控制台](http://unicloud.dcloud.net.cn/),在`用户管理页面`中,点击“登录设置”,点击“登录设置”,然后在“匿名登录”一栏打开/关闭可用状态。
-
-![uniCloud匿名登录](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uniCloud/auth-anonymously.png)
-
-### 客户端进行匿名登录
-```js
-await auth.signInAnonymously().catch(err=>{
- // 登录失败会抛出错误
-});
-// 匿名登录成功检测登录状态isAnonymous字段为true
-const loginState = await auth.getLoginState();
-console.log(loginState.isAnonymous) // true
-```
-
#### 匿名用户重新登录
-匿名用户如果要重新使用开发者提供的身份登录,可以调用`auth.signInWithTicket`来进行。[参考](#客户端上使用Ticket登录)
+匿名用户如果要重新使用开发者提供的身份登录,可以调用`auth.signInWithTicket`来进行。[参考](#signinwithticket)
-#### 匿名用户转化为自定义用户
-目前UniCloud支持将匿名用户转化为自定义登录用户,此转正用户将会继承匿名用户在云端创建的资源,流程如下:
-1. 首先需要按照自定义登录的流程搭建获取自定义登录凭证`ticket`的服务;
+#### 匿名用户转化为正式用户
+目前uniCloud支持将匿名用户转化为正式用户,此转正用户将会继承匿名用户在云端创建的资源,流程如下:
+1. 首先需要按照[登录流程](#cloudtoken)搭建获取自定义登录凭证`ticket`的服务;
2. 客户端请求接口获取自定义登录凭证`ticket`。**请注意**,此`ticket`必须未注册过uniCloud,换句话说,匿名用户只能转化为新的uniCloud用户;
3. 客户端调用`auth.linkAndRetrieveDataWithTicket`API,如下:
```js
@@ -195,7 +163,7 @@ uniCloud.on('loginStateExpire', () => {
JS SDK 会在登录态生效期间,自动刷新和维护短期访问令牌(access token),每次成功刷新时会触发此事件。
-对于两种登录态并存(uniCloud、自身业务登录态)的 Web 应用,这个事件可以用于同步登录态之间的状态。
+对于两种登录态并存(uniCloud、自身业务登录态)的应用,这个事件可以用于同步登录态之间的状态。
```js
uniCloud.on('refreshAccessToken', () => {
@@ -207,7 +175,7 @@ uniCloud.on('refreshAccessToken', () => {
`shouldRefreshAccessToken` 接收一个 `callback` 函数,并且会在刷新短期访问令牌前调用此 `callback` 函数,根据返回值决定是否要刷新短期访问令牌。
-对于两种登录态并存(uniCloud、自身业务登录态)的 Web 应用,可以在 `callback` 内判断自身业务登录态是否失效,从而决定是否续期 uniCloud 的短期访问令牌。
+对于两种登录态并存(uniCloud、自身业务登录态)的应用,可以在 `callback` 内判断自身业务登录态是否失效,从而决定是否续期 uniCloud 的短期访问令牌。
```js
auth.shouldRefreshAccessToken(() => {
diff --git a/docs/uniCloud/cf-authentication.md b/docs/uniCloud/cf-authentication.md
index 9de7afc04589bd02884d483e65ff5511c721f527..055ce18419346dd99d85c3b41a3b9daa8fce8904 100644
--- a/docs/uniCloud/cf-authentication.md
+++ b/docs/uniCloud/cf-authentication.md
@@ -21,13 +21,31 @@ const {
### auth.getClientIP()
-获取客户端IP地址
+获取客户端IP地址,上传并运行时返回空
```js
const IP = auth.getClientIP()
```
-### auth.createTicket(String customUserId, Object createTicketOptions)
+### auth.createTicket(String customUserId, Object createTicketOptions)@createticket
+
+此Api现在直接调用有问题,正在修复。可以先使用下面的方式调用
+
+```js
+const app = uniCloud.init({
+ spaceId: 'your-space-id',
+ credentials: require('./credentials.json')
+})
+
+const auth = app.auth();
+
+let customUserId = '123456';
+
+const ticket = auth.createTicket(customUserId, {
+ refresh: 10 * 60 * 1000 // 每十分钟刷新一次登录态, 默认为一小时
+});
+```
+
开发者可以使用云函数创建登录凭证,提供给客户端进行登录操作。[详见](uniCloud/authentication.md#自定义登录)
@@ -43,5 +61,5 @@ let customUserId = '123456';
const ticket = auth.createTicket(customUserId, {
refresh: 10 * 60 * 1000 // 每十分钟刷新一次登录态, 默认为一小时
});
-// 然后把 ticket 发送给客户端
+// 然后把 ticket 发送给客户端,由客户端调用auth.signInWithTicket()使用
```
diff --git a/docs/uniCloud/cf-common.md b/docs/uniCloud/cf-common.md
new file mode 100644
index 0000000000000000000000000000000000000000..78c3a5b28baf97d586f69577880e5ab60dbd1fac
--- /dev/null
+++ b/docs/uniCloud/cf-common.md
@@ -0,0 +1,86 @@
+#### 云函数公用模块
+
+自`HBuilderX 2.6.6-alpha`起,uniCloud提供了云函数模块公用方案。以下面的目录结构为例,介绍一下如何使用。
+
+```
+|--cloudfunctions
+ |--common // 云函数公用模块目录
+ |--hello-common // 云函数公用模块
+ |--package.json
+ |--index.js // 公用模块代码,可以不使用index.js,修改 package.json 内的 main 字段可以指定此文件名
+ |--use-common // 使用公用模块的云函数
+ |--package.json // 在 use-common 目录执行 npm init -y 生成
+ |--index.js // 云函数入口文件
+```
+
+**创建并引入公用模块**
+
+1. 在`cloudfunctions`目录下创建`common`目录
+2. 在`common`目录右键创建公用模块目录(本例中为`hello-common`,见下方示例图),会自动创建入口`index.js`文件和`package.json`,**不要修改此package.json的name字段**
+3. 在`hello-common`右键上传公用模块
+4. 在要引入公用模块的云函数目录(本例中为`use-common`)执行`npm init -y`生成`package.json`文件
+5. 在`use-common`目录执行`npm install ../common/hello-common`引入`hello-common`模块
+
+![创建公用模块](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uniCloud/create-common-module.jpg)
+
+**注意事项**
+
+- 如需修改公用模块需要在`common`目录下修改,修改之后不需要重新执行`npm install`。
+- 如果要更新所有依赖某公用模块的云函数,可以在`common`目录下的公用模块目录(本例中为`hello-common`)右键选择`更新依赖本模块的云函数`
+- 公用模块命名不可与nodejs内置模块重名
+- 安装公用模块时不推荐使用yarn,与`npm install`表现不一样,yarn不会创建软链接而是直接拷贝文件到node_modules,这样会导致修改公用模块云函数内引用的公用模块不会同步修改
+- 从插件市场导入或者其他地方复制项目可能会导致`npm install`创建的软链接失效,如果遇到这种情况请删除`node_modules`和`package-lock.json`重新`npm install`
+
+![更新公用模块](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uniCloud/update-common-module.jpg)
+
+**使用公用模块**
+
+仍以上面的目录为例,在公用模块内`exports`,在云函数内`require`即可。示例代码如下:
+
+```js
+// common/hello-common/index.js
+function getVersion() {
+ return '0.0.1'
+}
+module.exports = {
+ getVersion,
+ secret: 'your secret'
+}
+```
+
+```js
+// use-common/index.js
+'use strict';
+const {
+ secret,
+ getVersion
+} = require('hello-common')
+exports.main = async (event, context) => {
+ let version = getVersion()
+ return {
+ secret,
+ version
+ }
+}
+```
+
+如果仅需要导出一个function还可以使用以下写法
+
+```js
+// common/hello-common/index.js
+module.exports = function(e){
+ return e
+}
+```
+
+```js
+// use-common/index.js
+'use strict';
+const echo = require('hello-common')
+exports.main = async (event, context) => {
+ let eventEcho = echo(event)
+ return {
+ eventEcho
+ }
+}
+```
diff --git a/docs/uniCloud/cf-database.md b/docs/uniCloud/cf-database.md
index b79c320374c3aeff39fec020357d82489353e83d..c6842d8bd1bf0a9c0e3f1656b70d54d3db35db1c 100644
--- a/docs/uniCloud/cf-database.md
+++ b/docs/uniCloud/cf-database.md
@@ -1,9376 +1,9583 @@
-## 云数据库简介
-
-`uniCloud`提供了一个 JSON 格式的文档型数据库,数据库中的每条记录都是一个 JSON 格式的对象。一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。
-
-关系型数据库和 JSON 文档型数据库的概念对应关系如下表:
-
-|关系型 |JSON 文档型 |
-|:- |:- |
-|数据库 database|数据库 database |
-|表 table |集合 collection |
-|行 row |记录 record / doc|
-|列 column |字段 field |
-
-`uniCloud`云函数中可访问云数据库。
-
-鉴于安全问题,暂不支持客户端直接访问数据库。
-
-**阿里云使用的mongoDB数据库版本为3.4,腾讯云使用的版本是4.0。此差异可能会导致本文档内的部分功能不能在阿里云使用,我们会进行标注,如果发现有遗漏欢迎向我们反馈**
-
-**如果不想使用此数据库,可以自行连接其他数据库,用法可以参考nodejs连接数据库**
-
-## 获取数据库的引用
-
-```js
-const db = uniCloud.database();
-```
-
-**DBOptions参数说明**
-
-|字段 |类型 |必填 |描述 |平台差异说明 |
-|:-: |:-: |:-: |:-: |:-: |
-|spaceId|String |否 |同一账号下的,服务空间ID |仅腾讯云支持 |
-
-## 新增集合
-
-如果集合已存在,则报错。
-
-**平台差异说明**
-
-|阿里云 |腾讯云 |
-|---- |---- |
-|× |√ |
-
-```
-db.createCollection(collectionName)
-```
-
-## 获取集合的引用
-
-```js
-// 获取 `user` 集合的引用
-const collection = db.collection('user');
-```
-
-### 集合 Collection
-
-通过 `db.collection(name)` 可以获取指定集合的引用,在集合上可以进行以下操作
-
-| 类型 | 接口 | 说明 |
-| -------- | ------- | ---------------------------------------------------------------------------------- |
-| 写 | add | 新增记录(触发请求) |
-| 计数 | count | 获取符合条件的记录条数 |
-| 读 | get | 获取集合中的记录,如果有使用 where 语句定义查询条件,则会返回匹配结果集 (触发请求) |
-| 引用 | doc | 获取对该集合中指定 id 的记录的引用 |
-| 查询条件 | where | 通过指定条件筛选出匹配的记录,可搭配查询指令(eq, gt, in, ...)使用 |
-| | skip | 跳过指定数量的文档,常用于分页,传入 offset |
-| | orderBy | 排序方式 |
-| | limit | 返回的结果集(文档数量)的限制,有默认值和上限值 |
-| | field | 指定需要返回的字段 |
-
-
-查询及更新指令用于在 `where` 中指定字段需满足的条件,指令可通过 `db.command` 对象取得。
-
-
-### 记录 Record / Document
-
-通过 `db.collection(collectionName).doc(docId)` 可以获取指定集合上指定 id 的记录的引用,在记录上可以进行以下操作
-
-| 接口| 说明 | |
-| ----| ------|---- |
-| 写 | set | 覆写记录 |
-| | update| 局部更新记录(触发请求)|
-| | remove| 删除记录(触发请求) |
-| 读 | get | 获取记录(触发请求) |
-
-
-### 查询筛选指令 Query Command
-
-以下指令挂载在 `db.command` 下
-
-| 类型 | 接口 | 说明 |
-| -------- | ---- | ---------------------------------- |
-| 比较运算 | eq | 字段等于 == |
-| | neq | 字段不等于 != |
-| | gt | 字段大于 > |
-| | gte | 字段大于等于 >= |
-| | lt | 字段小于 < |
-| | lte | 字段小于等于 <= |
-| | in | 字段值在数组里 |
-| | nin | 字段值不在数组里 |
-| 逻辑运算 | and | 表示需同时满足指定的所有条件 |
-| | or | 表示需同时满足指定条件中的至少一个 |
-
-如果你熟悉SQL,可查询[mongodb与sql语句对照表](https://blog.csdn.net/xinghebuluo/article/details/7012788/)进行学习。
-
-### 字段更新指令 Update Command
-
-以下指令挂载在 `db.command` 下
-
-| 类型 | 接口 | 说明 |
-| ---- | ------- | -------------------------------- |
-| 字段 | set | 设置字段值 |
-| | remove | 删除字段 |
-| | inc | 加一个数值,原子自增 |
-| | mul | 乘一个数值,原子自乘 |
-| | push | 数组类型字段追加尾元素,支持数组 |
-| | pop | 数组类型字段删除尾元素,支持数组 |
-| | shift | 数组类型字段删除头元素,支持数组 |
-| | unshift | 数组类型字段追加头元素,支持数组 |
-
-
-## 支持的数据类型
-
-数据库提供以下几种数据类型:
-* String:字符串
-* Number:数字
-* Object:对象
-* Array:数组
-* Bool:布尔值
-* GeoPoint:地理位置点
-* GeoLineStringL: 地理路径
-* GeoPolygon: 地理多边形
-* GeoMultiPoint: 多个地理位置点
-* GeoMultiLineString: 多个地理路径
-* GeoMultiPolygon: 多个地理多边形
-* Date:时间
-* Null
+## 云数据库简介
+
+`uniCloud`提供了一个 JSON 格式的文档型数据库,数据库中的每条记录都是一个 JSON 格式的对象。一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。
+
+关系型数据库和 JSON 文档型数据库的概念对应关系如下表:
+
+|关系型 |JSON 文档型 |
+|:- |:- |
+|数据库 database|数据库 database |
+|表 table |集合 collection |
+|行 row |记录 record / doc|
+|列 column |字段 field |
+
+**云数据库仅支持通过云函数可访问。如需要在客户端访问云数据库,需通过`clientDB`插件。该插件可以将所有数据库操作封装在一个云函数中,大幅提升开发效率,是uniCloud开发者的必备插件,详见:[https://uniapp.dcloud.io/uniCloud/uni-clientDB](https://uniapp.dcloud.io/uniCloud/uni-clientDB)**
+
+**阿里云使用的mongoDB数据库版本为4.0,腾讯云使用的腾讯云自研的文档型数据库(兼容mongoDB 4.0版本)。请注意API的兼容性说明**
+
+如果同时还想连接其他数据库,如mysql/redis,用法可以参考如下插件:
+
+- [云函数连接Mysql数据库示例](https://ext.dcloud.net.cn/plugin?id=1925)
+- [云函数连接Redis数据库示例](https://ext.dcloud.net.cn/plugin?id=1846)
+
+## 获取数据库的引用
+
+```js
+const db = uniCloud.database();
+```
+
+**DBOptions参数说明**
+
+|字段 |类型 |必填 |描述 |平台差异说明 |
+|:-: |:-: |:-: |:-: |:-: |
+|spaceId|String |否 |同一账号下的,服务空间ID |仅腾讯云支持 |
+
+## 新增集合
+
+如果集合已存在,则报错。
+
+**平台差异说明**
+
+|阿里云 |腾讯云 |
+|---- |---- |
+|× |√ |
+
+```
+db.createCollection(collectionName)
+```
+
+阿里云的集合需提前在web控制台创建。
+
+## 使用db\_init.json初始化项目数据库@db-init
+
+自`HBuilderX 2.5.11`起`uniCloud`提供了`db_init.json`来方便开发者快速进行数据库的初始化操作,即在HBuilderX工具中,将本地数据直接同步到云数据库中。
+
+这个功能尤其适合插件作者,可以快速初始化集合和数据。
+
+**使用方式**
+- 在`cloudfucntions`目录右键即可创建`db_init.json`,
+- 编写好json内容,在`db_init.json`上右键初始化数据库。
+
+**注意事项**
+- 目前`db_init.json`为同步导入形式,无法导入大量数据,后续会实现异步导入方案。
+
+**db_init.json形式如下**
+
+```
+{
+ "collection_test": { // 集合(表名)
+ "data": [ // 数据
+ {
+ "_id": "da51bd8c5e37ac14099ea43a2505a1a5",
+ "name": "tom"
+ }
+ ],
+ "index": [{ // 索引
+ "IndexName": "index_a", // 索引名称
+ "MgoKeySchema": { // 索引规则
+ "MgoIndexKeys": [{
+ "Name": "index", // 索引字段
+ "Direction": "1" // 索引方向,1:ASC-升序,-1:DESC-降序,2dsphere:地理位置
+ }],
+ "MgoIsUnique": false // 索引是否唯一
+ }
+ }]
+ }
+}
+```
+
+## 数据库回档@backup
+
+**此功能暂时只有腾讯云支持**
+
+uniCloud会在每天备份一次数据库,最多保留7天。
+
+**操作说明**
+
+1. 登录[uniCloud后台](https://unicloud-dev.dcloud.net.cn/)
+2. 点击左侧菜单`云数据库 --> 数据库回档`,点击`新建回档`
+3. 选择可回档时间
+4. 选择需要回档的集合(注意:回档后集合不能与现有集合重名,如需对集合重命名可以在集合列表处操作)
+
+![数据库回档](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uniCloud/unicloud-db-backup.jpg)
+
+## 数据导出@export
+
+**此功能暂时只有阿里云支持**
+
+此功能主要用于导出整个集合的数据
+
+**用法**
+
+1. 进入[uniCloud web控制台](https://unicloud.dcloud.net.cn/home),选择服务空间,或者直接在HBuilderX云函数目录`cloudfunctions`上右键打开uniCloud web控制台
+2. 进入云数据库选择希望导入数据的集合
+3. 点击导出按钮
+4. 选择导出格式,如果选择csv格式还需要选择导出字段
+5. 点击确定按钮等待下载开始即可
**注意**
-- 阿里云数据库在存入emoji表情时会导致uniCloud控制台无法获取数据列表,目前阿里正在处理此问题,开发者可以先自行过滤一下
-
-以下对几个特殊的数据类型做个补充说明
-### 时间 Date
-
- Date 类型用于表示时间,精确到毫秒,可以用 JavaScript 内置 Date 对象创建。需要特别注意的是,用此方法创建的时间是客户端时间,不是服务端时间。如果需要使用服务端时间,应该用 API 中提供的 serverDate 对象来创建一个服务端当前时间的标记,当使用了 serverDate 对象的请求抵达服务端处理时,该字段会被转换成服务端当前的时间,更棒的是,我们在构造 serverDate 对象时还可通过传入一个有 offset 字段的对象来标记一个与当前服务端时间偏移 offset 毫秒的时间,这样我们就可以达到比如如下效果:指定一个字段为服务端时间往后一个小时。
-
- 那么当我们需要使用客户端时间时,存放 Date 对象和存放毫秒数是否是一样的效果呢?不是的,我们的数据库有针对日期类型的优化,建议大家使用时都用 Date 或 serverDate 构造时间对象。
-
- ```js
- //服务端当前时间
- new db.serverDate()
- ```
-
- ```js
- //服务端当前时间加1S
- new db.serverDate({
- offset: 1000
- })
- ```
-
-**Tips**
-
-- 使用阿里云作为服务提供商时,如需存入日期类型,需要`2020-02-10T04:59:05.579Z`形式,即可以在云函数中使用`new Date().toISOString()`得到。
-
-### 地理位置
-
-**阿里云暂不支持地理位置类型**
-
-参考:[GEO地理位置](#GEO地理位置)
-
-### Null
-
- Null 相当于一个占位符,表示一个字段存在但是值为空。
-
-
-## 新增文档
-
-方法1: collection.add(data)
-
-示例:
-
-| 参数 | 类型 | 必填 | 说明 |
-| ---- | ------ | ---- | ---------------------------------------- |
-| data | object | array | 是 | {_id: '10001', 'name': 'Ben'} _id 非必填|
-
-```js
-// 单条插入数据
-let res = await collection.add({
- name: 'Ben'
-})
-// 批量插入数据
-let res = await collection.add([{
- name: 'Alex'
-},{
- name: 'Ben'
-},{
- name: 'John'
-}])
-// res.inserted // 插入成功条数
-// res.result // 阿里云特有,批量插入返回的所有记录 id
-// res.failIndexes // 腾讯云特有,插入失败的记录的下标
-```
-
-**Tips**
-
-- 云服务商为阿里云时,若集合不存在,调用add方法会自动创建集合
-
-方法2: collection.doc().set(data)
-
-也可通过 `set` 方法新增一个文档,需先取得文档引用再调用 `set` 方法。
-如果文档不存在,`set` 方法会创建一个新文档。
-
-```js
-let res = await collection.doc().set({
- name: "Hey"
-});
-```
-
-
-## 查询文档
-
-支持 `where()`、`limit()`、`skip()`、`orderBy()`、`get()`、`update()`、`field()`、`count()` 等操作。
-
-只有当调用`get()` `update()`时才会真正发送请求。
-注:默认取前100条数据,最大取前100条数据。
-
-### 添加查询条件
-
-collection.where()
-参数
-
-设置过滤条件
-where 可接收对象作为参数,表示筛选出拥有和传入对象相同的 key-value 的文档。比如筛选出所有类型为计算机的、内存为 8g 的商品:
-
-```js
-let res = await db.collection('goods').where({
- category: 'computer',
- type: {
- memory: 8,
- }
-}).get()
-```
-
-如果要表达更复杂的查询,可使用高级查询指令,比如筛选出所有内存大于 8g 的计算机商品:
-```js
-const dbCmd = db.command // 取指令
-db.collection('goods').where({
- category: 'computer',
- type: {
- memory: dbCmd.gt(8), // 表示大于 8
- }
-})
-```
-
-`where` 可以使用正则表达式来查询文档,比如一下示例查询所有`name`字段以ABC开头的用户
-```js
-db.collection('user').where({
- name: new RegExp('^ABC')
-})
-```
-
-### 获取查询数量
-
-collection.count()
-
-参数
-```js
-let res = await db.collection('goods').where({
- category: 'computer',
- type: {
- memory: 8,
- }
-}).count()
-```
-
-响应参数
-
-| 字段 | 类型 | 必填 | 说明 |
-| --------- | ------- | ---- | ------------------------ |
-| code | string | 否 | 状态码,操作成功则不返回 |
-| message | string | 否 | 错误描述 |
-| total | Integer | 否 | 计数结果 |
-| requestId | string | 否 | 请求序列号,用于错误排查 |
-
-
-
-### 设置记录数量
-
-collection.limit()
-
-参数说明
-
-| 参数 | 类型 | 必填 | 说明 |
-| ----- | ------- | ---- | -------------- |
-| value | Integer | 是 | 限制展示的数值 |
-
-使用示例
-
-```js
-let res = await collection.limit(1).get()
-```
-
-### 设置起始位置
-
-collection.skip()
-
-参数说明
-
-| 参数 | 类型 | 必填 | 说明 |
-| ----- | ------- | ---- | -------------- |
-| value | Integer | 是 | 跳过展示的数据 |
-
-使用示例
-
-```js
-let res = await collection.skip(4).get()
-```
-
-### 对结果排序
-
-collection.orderBy()
-
-参数说明
-
-| 参数 | 类型 | 必填 | 说明 |
-| --------- | ------ | ---- | ----------------------------------- |
-| field | string | 是 | 排序的字段 |
-| orderType | string | 是 | 排序的顺序,升序(asc) 或 降序(desc) |
-
-使用示例
-
-```js
-let res = await collection.orderBy("name", "asc").get()
-```
-
-### 指定返回字段
-
-collection.field()
-
-参数说明
-
-| 参数 | 类型 | 必填 | 说明 |
-| ---- | ------ | ---- | --------------------------------------- |
-| - | object | 是 | 要过滤的字段,不返回传false,返回传true |
-
-使用示例
-
-```js
-collection.field({ 'age': true })
-```
-备注:只能指定要返回的字段或者不要返回的字段。即{'a': true, 'b': false}是一种错误的参数格式
-
-### 查询指令
-#### eq
-
-表示字段等于某个值。`eq` 指令接受一个字面量 (literal),可以是 `number`, `boolean`, `string`, `object`, `array`。
-
-比如筛选出所有自己发表的文章,除了用传对象的方式:
-
-```js
-const myOpenID = "xxx"
-let res = await db.collection('articles').where({
- _openid: myOpenID
-}).get()
-```
-
-还可以用指令:
-
-```js
-const dbCmd = db.command
-const myOpenID = "xxx"
-let res = await db.collection('articles').where({
- _openid: dbCmd.eq(openid)
-}).get()
-```
-
-注意 `eq` 指令比对象的方式有更大的灵活性,可以用于表示字段等于某个对象的情况,比如:
-
-```js
-// 这种写法表示匹配 stat.publishYear == 2018 且 stat.language == 'zh-CN'
-let res = await db.collection('articles').where({
- stat: {
- publishYear: 2018,
- language: 'zh-CN'
- }
-}).get()
-// 这种写法表示 stat 对象等于 { publishYear: 2018, language: 'zh-CN' }
-const dbCmd = db.command
-let res = await db.collection('articles').where({
- stat: dbCmd.eq({
- publishYear: 2018,
- language: 'zh-CN'
- })
-}).get()
-```
-
-#### neq
-
-字段不等于。`neq` 指令接受一个字面量 (literal),可以是 `number`, `boolean`, `string`, `object`, `array`。
-
-如筛选出品牌不为 X 的计算机:
+- 导出的json文件并非一般情况下的json,而是每行一条json数据的文本文件
+- 导出为csv时必须填写字段选项。字段之间使用英文逗号隔开。例如:`_id, name, age, gender`
+- 数据量较大时可能需要等待一段时间才可以开始下载
-```js
-const dbCmd = db.command
-let res = await db.collection('goods').where({
- category: 'computer',
- type: {
- brand: dbCmd.neq('X')
- },
-}).get()
-```
-
-#### gt
-
-字段大于指定值。
-
-如筛选出价格大于 2000 的计算机:
-
-```js
-const dbCmd = db.command
-let res = await db.collection('goods').where({
- category: 'computer',
- price: dbCmd.gt(2000)
-}).get()
-```
-
-#### gte
-
-字段大于或等于指定值。
-
-#### lt
-
-字段小于指定值。
-
-#### lte
-
-字段小于或等于指定值。
-
-#### in
-
-字段值在给定的数组中。
-
-筛选出内存为 8g 或 16g 的计算机商品:
-
-```js
-const dbCmd = db.command
-let res = await db.collection('goods').where({
- category: 'computer',
- type: {
- memory: dbCmd.in([8, 16])
- }
-}).get()
-```
-
-#### nin
-
-字段值不在给定的数组中。
-
-筛选出内存不是 8g 或 16g 的计算机商品:
-
-```js
-const dbCmd = db.command
-db.collection('goods').where({
- category: 'computer',
- type: {
- memory: dbCmd.nin([8, 16])
- }
-})
-```
-
-#### and
-
-表示需同时满足指定的两个或以上的条件。
-
-如筛选出内存大于 4g 小于 32g 的计算机商品:
-
-流式写法:
-```js
-const dbCmd = db.command
-db.collection('goods').where({
- category: 'computer',
- type: {
- memory: dbCmd.gt(4).and(dbCmd.lt(32))
- }
-})
-```
-
-前置写法:
-```js
-const dbCmd = db.command
-db.collection('goods').where({
- category: 'computer',
- type: {
- memory: dbCmd.and(dbCmd.gt(4), dbCmd.lt(32))
- }
-})
-```
-
-#### or
-
-表示需满足所有指定条件中的至少一个。如筛选出价格小于 4000 或在 6000-8000 之间的计算机:
-
-流式写法:
-```js
-const dbCmd = db.command
-db.collection('goods').where({
- category: 'computer',
- type: {
- price:dbCmd.lt(4000).or(dbCmd.gt(6000).and(dbCmd.lt(8000)))
- }
-})
-```
-
-前置写法:
-```js
-const dbCmd = db.command
-db.collection('goods').where({
- category: 'computer',
- type: {
- price: dbCmd.or(dbCmd.lt(4000), dbCmd.and(dbCmd.gt(6000), dbCmd.lt(8000)))
- }
-})
-```
-
-如果要跨字段 “或” 操作:(如筛选出内存 8g 或 cpu 3.2 ghz 的计算机)
-
-```js
-const dbCmd = db.command
-db.collection('goods').where(dbCmd.or(
- {
- type: {
- memory: dbCmd.gt(8)
- }
- },
- {
- type: {
- cpu: 3.2
- }
- }
-))
-```
-
-### 正则表达式查询
-
-#### db.RegExp
-
-根据正则表达式进行筛选
-
-例如下面可以筛选出 `version` 字段开头是 "数字+s" 的记录,并且忽略大小写:
-```js
-// 可以直接使用正则表达式
-db.collection('articles').where({
- version: /^\ds/i
-})
-
-// 或者
-db.collection('articles').where({
- version: new db.RegExp({
- regex: '^\\ds' // 正则表达式为 /^\ds/,转义后变成 '^\\ds'
- options: 'i' // i表示忽略大小写
- })
-})
-```
-
-## 删除文档
-
-**方式1 通过指定文档ID删除**
-
-collection.doc(_id).remove()
-
-```js
-// 清理全部数据
-let res = await collection.get()
-res.data.map(async(document) => {
- return await collection.doc(document.id).remove();
-});
-```
-
-**方式2 条件查找文档然后直接批量删除**
-
-collection.where().remove()
-
-```js
-// 删除字段a的值大于2的文档
-const dbCmd = db.command
-let res = await collection.where({
- a: dbCmd.gt(2)
-}).remove()
-```
-
-## 更新文档
-
-### 更新指定文档
-
-collection.doc().update()
-
-```js
-let res = await collection.doc('doc-id').update({
- name: "Hey",
- count: {
- fav: 1
- }
-});
-```
-
-```
-// 更新前
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 0,
- "follow": 0
- }
-}
-
-// 更新后
-{
- "_id": "xxx",
- "name": "Hey",
- "count": {
- "fav": 1,
- "follow": 0
- }
-}
-```
-
-更新数组时,已数组下标作为key即可,比如以下示例将数组arr内下标为1的值修改为 uniCloud
-
-```js
-let res = await collection.doc('doc-id').update({
- arr: {
- 1: "uniCloud"
- }
-})
-```
-
-```json
-// 更新前
-{
- "arr": ["hello", "world"]
-}
-// 更新后
-{
- "arr": ["hello", "uniCloud"]
-}
-```
-
-### 更新文档,如果不存在则创建
-
-collection.doc().set()
-
-**注意:**
-
-- 此方法会覆写已有字段,需注意与`update`表现不同,比如以下示例执行`set`之后`follow`字段会被删除
-
-```js
-let res = await collection.doc('doc-id').set({
- name: "Hey",
- count: {
- fav: 1
- }
-})
-```
-
-```json
-// 更新前
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 0,
- "follow": 0
- }
-}
-
-// 更新后
-{
- "_id": "xxx",
- "name": "Hey",
- "count": {
- "fav": 1
- }
-}
-```
-
-### 批量更新文档
-collection.update()
-
-```js
-const dbCmd = db.command
-let res = await collection.where({name: dbCmd.eq('hey')}).update({
- age: 18,
-})
-```
-
-
-### 更新操作符
-
-更多数据库操作符请查看[数据库操作符](#dbcmd)
-
-#### set
-
-更新指令。用于设定字段等于指定值。这种方法相比传入纯 JS 对象的好处是能够指定字段等于一个对象:
-
-```js
-const dbCmd = db.command
-let res = await db.collection('photo').doc('doc-id').update({
- count: dbCmd.set({
- fav: 1,
- follow: 1
- })
-})
-```
-
-```
-// 更新前
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 0,
- "follow": 0
- }
-}
-
-// 更新后
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 1,
- "follow": 1
- }
-}
-```
-
-#### inc
-
-更新指令。用于指示字段自增某个值,这是个原子操作,使用这个操作指令而不是先读数据、再加、再写回的好处是:
-
-1. 原子性:多个用户同时写,对数据库来说都是将字段加一,不会有后来者覆写前者的情况
-2. 减少一次网络请求:不需先读再写
-
-之后的 mul 指令同理。
-
-如给收藏的商品数量加一:
-
-```js
-const dbCmd = db.command
+## 数据导入@import
-let res = await db.collection('user').where({
- _id: 'my-doc-id'
-}).update({
- count: {
- fav: dbCmd.inc(1)
- }
-})
-```
-
-```
-// 更新前
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 0,
- "follow": 0
- }
-}
-
-// 更新后
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 1,
- "follow": 0
- }
-}
-```
-
-请注意并没有提供减法操作,如果要实现减法,也需通过inc实现。比如上述字段减1,
-
-```js
-const dbCmd = db.command
-
-let res = await db.collection('user').where({
- _id: 'my-doc-id'
-}).update({
- count: {
- fav: dbCmd.inc(-1)
- }
-})
-```
-
-#### mul
-
-更新指令。用于指示字段自乘某个值。
-
-以下示例将count内的fav字段乘10
-
-```js
-const dbCmd = db.command
-
-let res = await db.collection('user').where({
- _id: 'my-doc-id'
-}).update({
- count: {
- fav: dbCmd.mul(10)
- }
-})
-```
-
-```
-// 更新前
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 2,
- "follow": 0
- }
-}
-
-// 更新后
-{
- "_id": "xxx",
- "name": "Hello",
- "count": {
- "fav": 20,
- "follow": 0
- }
-}
-```
-
-请注意并没有提供除法操作,如果要实现除法,也需通过mul实现。比如上述字段除以10,
-
-```js
-const dbCmd = db.command
-
-let res = await db.collection('user').where({
- _id: 'my-doc-id'
-}).update({
- count: {
- fav: dbCmd.mul(0.1)
- }
-})
-```
-
-#### remove
+**此功能暂时只有阿里云支持**
-更新指令。用于表示删除某个字段。如某人删除了自己一条商品评价中的评分:
+之前uniCloud提供的`db_init.json`主要是为了对数据库进行初始化,并不适合导入大量数据。与`db_init.json`不同,数据导入功能可以导入大量数据,目前支持导出 CSV、JSON 格式的文件数据。
-```js
-const dbCmd = db.command
-let res = await db.collection('comments').doc('comment-id').update({
- rating: dbCmd.remove()
-})
-```
-
-```
-// 更新前
-{
- "_id": "xxx",
- "rating": 5,
- "comment": "xxx"
-}
-
-// 更新后
-{
- "_id": "xxx",
- "comment": "xxx"
-}
-```
-
-#### push
-向数组尾部追加元素,支持传入单个元素或数组
+**用法**
-```js
-const dbCmd = db.command
+1. 进入[uniCloud web控制台](https://unicloud.dcloud.net.cn/home),选择服务空间,或者直接在HBuilderX云函数目录`cloudfunctions`上右键打开uniCloud web控制台
+2. 进入云数据库选择希望导入数据的集合
+3. 点击导入,选择json文件或csv文件
+4. 选择处理冲突模式(关于处理冲突模式请看下方注意事项)
+5. 点击确定按钮等待导入完成即可
-let res = await db.collection('comments').doc('comment-id').update({
- // users: dbCmd.push('aaa')
- users: dbCmd.push(['c', 'd'])
-})
-```
-
-```json
-// 更新前
-{
- "_id": "xxx",
- "users": ["a","b"]
-}
-
-// 更新后
-{
- "_id": "xxx",
- "users": ["a","b","c","d"]
-}
-```
-
-#### pop
-删除数组尾部元素
-
-```js
-const dbCmd = db.command
-
-let res = await db.collection('comments').doc('comment-id').update({
- users: dbCmd.pop()
-})
-```
-
-```json
-// 更新前
-{
- "_id": "xxx",
- "users": ["a","b"]
-}
-
-// 更新后
-{
- "_id": "xxx",
- "users": ["a"]
-}
-```
-
-#### unshift
-向数组头部添加元素,支持传入单个元素或数组。使用同push
-
-```js
-const dbCmd = db.command
-
-let res = await db.collection('comments').doc('comment-id').update({
- // users: dbCmd.push('aaa')
- users: dbCmd.unshift(['c', 'd'])
-})
-```
-
-```json
-// 更新前
-{
- "_id": "xxx",
- "users": ["a","b"]
-}
-
-// 更新后
-{
- "_id": "xxx",
- "users": ["c","d","a","b"]
-}
-```
-
-#### shift
-删除数组头部元素。使用同pop
-
-```js
-const dbCmd = db.command
-
-let res = await db.collection('comments').doc('comment-id').update({
- users: dbCmd.shift()
-})
-```
-
-```json
-// 更新前
-{
- "_id": "xxx",
- "users": ["a","b"]
-}
-
-// 更新后
-{
- "_id": "xxx",
- "users": ["b"]
-}
-```
-
-## GEO地理位置
-
-注意:**如果需要对类型为地理位置的字段进行搜索,一定要建立地理位置索引**。
-
-**平台差异说明**
-
-|阿里云 |腾讯云 |
-|---- |---- |
-|× |√ |
-
-
-### GEO数据类型
-
-#### Point
-
-用于表示地理位置点,用经纬度唯一标记一个点,这是一个特殊的数据存储类型。
-
-签名:`Point(longitude: number, latitude: number)`
-
-示例:
-```js
-new db.Geo.Point(longitude, latitude)
-```
-
-#### LineString
-
-用于表示地理路径,是由两个或者更多的 `Point` 组成的线段。
-
-签名:`LineString(points: Point[])`
-
-示例:
-
-```js
-new db.Geo.LineString([
- new db.Geo.Point(lngA, latA),
- new db.Geo.Point(lngB, latB),
- // ...
-])
-```
-
-#### Polygon
-
-用于表示地理上的一个多边形(有洞或无洞均可),它是由一个或多个**闭环** `LineString` 组成的几何图形。
-
-由一个环组成的 `Polygon` 是没有洞的多边形,由多个环组成的是有洞的多边形。对由多个环(`LineString`)组成的多边形(`Polygon`),第一个环是外环,所有其他环是内环(洞)。
-
-签名:`Polygon(lines: LineString[])`
-
-示例:
-
-```js
-new db.Geo.Polygon([
- new db.Geo.LineString(...),
- new db.Geo.LineString(...),
- // ...
-])
-```
-
-#### MultiPoint
-
-用于表示多个点 `Point` 的集合。
-
-签名:`MultiPoint(points: Point[])`
-
-示例:
-
-```js
-new db.Geo.MultiPoint([
- new db.Geo.Point(lngA, latA),
- new db.Geo.Point(lngB, latB),
- // ...
-])
-```
-
-#### MultiLineString
-
-用于表示多个地理路径 `LineString` 的集合。
-
-签名:`MultiLineString(lines: LineString[])`
-
-示例:
-
-```js
-new db.Geo.MultiLineString([
- new db.Geo.LineString(...),
- new db.Geo.LineString(...),
- // ...
-])
-```
-
-
-#### MultiPolygon
-
-用于表示多个地理多边形 `Polygon` 的集合。
-
-签名:`MultiPolygon(polygons: Polygon[])`
-
-示例:
-
-```js
-new db.Geo.MultiPolygon([
- new db.Geo.Polygon(...),
- new db.Geo.Polygon(...),
- // ...
-])
-```
-
-### GEO操作符
-
-#### geoNear
-
-按从近到远的顺序,找出字段值在给定点的附近的记录。
-
-签名:
-```js
-db.command.geoNear(options: IOptions)
-
-interface IOptions {
- geometry: Point // 点的地理位置
- maxDistance?: number // 选填,最大距离,米为单位
- minDistance?: number // 选填,最小距离,米为单位
-}
-```
-
-
-示例:
-
-```js
-let res = await db.collection('user').where({
- location: db.command.geoNear({
- geometry: new db.Geo.Point(lngA, latA),
- maxDistance: 1000,
- minDistance: 0
- })
-}).get()
-```
-
-#### geoWithin
-
-找出字段值在指定 Polygon / MultiPolygon 内的记录,无排序
-
-签名:
-
-```js
-db.command.geoWithin(IOptions)
-
-interface IOptions {
- geometry: Polygon | MultiPolygon // 地理位置
-}
-```
-
-示例:
-
-```js
-// 一个闭合的区域
-const area = new Polygon([
- new LineString([
- new Point(lngA, latA),
- new Point(lngB, latB),
- new Point(lngC, latC),
- new Point(lngA, latA)
- ]),
-])
-
-// 搜索 location 字段在这个区域中的 user
-let res = await db.collection('user').where({
- location: db.command.geoWithin({
- geometry: area
- })
-}).get()
-```
-
-#### geoIntersects
-
-找出字段值和给定的地理位置图形相交的记录
-
-签名:
-
-```js
-db.command.geoIntersects(IOptions)
-
-interface IOptions {
- geometry: Point | LineString | MultiPoint | MultiLineString | Polygon | MultiPolygon // 地理位置
-}
-```
-
-示例:
-
-```js
-// 一条路径
-const line = new LineString([
- new Point(lngA, latA),
- new Point(lngB, latB)
-])
-
-// 搜索 location 与这条路径相交的 user
-let res = await db.collection('user').where({
- location: db.command.geoIntersects({
- geometry: line
- })
-}).get()
-```
-
-
-
-## 事务
-
-**目前仅腾讯云支持事务,阿里云暂不支持**
-
-事务通常用来在某个数据库操作失败之后进行回滚。
-
-### runTransaction
-
-发起事务。与`startTransaction`作用类似,接收参数类型不同
-
-**`runTransaction` 的形式如下:**
-
-```javascript
-db.runTransaction(callback: function, times: number)
-```
-
-**参数**
-
-|参数 |类型 |说明 |
-|--- |--- |--- |
-|callback |Function |事务执行函数,需为 async 异步函数或返回 Promise 的函数 |
-|times |Number |事务执行最多次数,默认 3 次,成功后不重复执行,只有事务冲突时会重试,其他异常时不会重试|
-
-**返回值**
-
-`runTransaction`返回一个`Promise`,此`Promise.resolve`的结果为`callback`事务执行函数的返回值,`reject` 的结果为事务执行过程中抛出的异常或者是 `transaction.rollback` 传入的值
-
-**callback 事务执行函数的说明**
-
-事务执行函数由开发者传入,函数接收一个参数 transaction,其上提供 collection 方法和 rollback 方法。collection 方法用于取数据库集合记录引用进行操作,rollback 方法用于在不想继续执行事务时终止并回滚事务。
-
-事务执行函数必须为 `async` 异步函数或返回 `Promise` 的函数,当事务执行函数返回时,uniCloud 会认为用户逻辑已完成,自动提交(`commit`)事务,因此务必确保用户事务逻辑完成后才在 `async` 异步函数中返回或 `resolve Promise`。
-
-事务执行函数可能会被执行多次,在内部发现事务冲突时会自动重复执行,如果超过设定的执行次数上限,会报错退出。
-
-在事务执行函数中发生的错误,都会认为事务执行失败而抛错。
-
-事务执行函数返回的值会作为 `runTransaction` 返回的 `Promise resolve` 的值,在函数中抛出的异常会作为 `runTransaction` 返回的 `Promise reject` 的值,如果事务执行函数中调用了 `transaction.rollback`,则传入 `rollback` 函数的值会作为 `runTransaction` 返回的 `Promise reject` 的值。
-
-**限制**
-
-事务操作时为保障效率和并发性,只允许进行单记录操作,不允许进行批量操作,但可以在一个事务进行多次数据库操作。
-
-**注意事项**
-
-开发者提供的事务执行函数正常返回时,uniCloud 会自动提交(`commit`)事务,请勿在事务执行函数内调用 `transaction.commit` 方法,该方法仅在通过 `db.startTransaction` 进行事务操作时使用
-
-**示例代码**
-
-两个账户之间进行转账的简易示例
-
-```javascript
-const db = uniCloud.database()
-const _ = db.command
-exports.main = async (event) => {
- try {
- const result = await db.runTransaction(async transaction => {
- const aaaRes = await transaction.collection('account').doc('aaa').get()
- const bbbRes = await transaction.collection('account').doc('bbb').get()
-
- if (aaaRes.data && bbbRes.data) {
- const updateAAARes = await transaction.collection('account').doc('aaa').update({
- data: {
- amount: _.inc(-10)
- }
- })
-
- const updateBBBRes = await transaction.collection('account').doc('bbb').update({
- data: {
- amount: _.inc(10)
- }
- })
-
- console.log(`transaction succeeded`)
-
- // 会作为 runTransaction resolve 的结果返回
- return {
- aaaAccount: aaaRes.data.amount - 10,
- }
- } else {
- // 会作为 runTransaction reject 的结果出去
- await transaction.rollback(-100)
- }
- })
-
- return {
- success: true,
- aaaAccount: result.aaaAccount,
- }
- } catch (e) {
- console.error(`transaction error`, e)
-
- return {
- success: false,
- error: e
- }
- }
-}
-```
-
-### startTransaction
-
-发起事务。与`runTransaction`作用类似,接收参数类型不同
-
-**`startTransaction` 形式如下**
-
-```javascript
-// 与runTransaction不同,startTransaction不接收参数
-db.startTransaction()
-```
-
-**返回值**
-
-返回一个`Promise`,此`Promise resolve`的结果为事务操作对象(**注意这里与runTransaction的区别**),其上可通过 `collection API` 操作数据库,通过 `commit`(**使用`startTransaction`需要主动`commit`**) 或 `rollback` 来结束或终止事务。
-
-**限制**
-
-事务操作时为保障效率和并发性,只允许进行单记录操作,不允许进行批量操作,但可以在一个事务进行多次数据库操作。
-
-**示例代码**
-
-两个账户之间进行转账的简易示例
-
-```javascript
-const db = uniCloud.database()
-const _ = db.command
-
-exports.main = async (event) => {
- try {
- const transaction = await db.startTransaction()
-
- const aaaRes = await transaction.collection('account').doc('aaa').get()
- const bbbRes = await transaction.collection('account').doc('bbb').get()
-
- if (aaaRes.data && bbbRes.data) {
- const updateAAARes = await transaction.collection('account').doc('aaa').update({
- data: {
- amount: _.inc(-10)
- }
- })
-
- const updateBBBRes = await transaction.collection('account').doc('bbb').update({
- data: {
- amount: _.inc(10)
- }
- })
-
- await transaction.commit()
-
- console.log(`transaction succeeded`)
-
- return {
- success: true,
- aaaAccount: aaaRes.data.amount - 10,
- }
- } else {
- await transaction.rollback()
-
- return {
- success: false,
- error: `rollback`,
- rollbackCode: -100,
- }
- }
- } catch (e) {
- console.error(`transaction error`, e)
-
- return {
- success: false,
- error: e
- }
- }
-}
-```
-
-## 聚合操作
-
-获取数据库集合的聚合操作实例
-```js
-db.collection('scores').aggregate()
-```
-
-### addFields
-
-聚合阶段。添加新字段到输出的记录。经过 `addFields` 聚合阶段,输出的所有记录中除了输入时带有的字段外,还将带有 `addFields` 指定的字段。
-
-
-**API 说明**
-
-`addFields` 等同于同时指定了所有已有字段和新增字段的 `project` 阶段。
-
-**`addFields` 的形式如下:**
-```js
-addFields({
- <新字段>: <表达式>
-})
-```
-`addFields` 可指定多个新字段,每个新字段的值由使用的表达式决定。
-
-如果指定的新字段与原有字段重名,则新字段的值会覆盖原有字段的值。注意 `addFields` 不能用来给数组字段添加元素。
-
-**示例 1:连续两次 addFields**
-
-假设集合 scores 有如下记录:
-```js
-{
- _id: 1,
- student: "Maya",
- homework: [ 10, 5, 10 ],
- quiz: [ 10, 8 ],
- extraCredit: 0
-}
-{
- _id: 2,
- student: "Ryan",
- homework: [ 5, 6, 5 ],
- quiz: [ 8, 8 ],
- extraCredit: 8
-}
-```
-应用两次 `addFields`,第一次增加两个字段分别为 `homework` 和 `quiz` 的和值,第二次增加一个字段再基于上两个和值求一次和值。
-```js
-const $ = db.command.aggregate
-let res = await db.collection('scores').aggregate()
- .addFields({
- totalHomework: $.sum('$homework'),
- totalQuiz: $.sum('$quiz')
- })
- .addFields({
- totalScore: $.add(['$totalHomework', '$totalQuiz', '$extraCredit'])
- })
- .end()
-```
-
-返回结果如下:
-```js
-{
- "_id" : 1,
- "student" : "Maya",
- "homework" : [ 10, 5, 10 ],
- "quiz" : [ 10, 8 ],
- "extraCredit" : 0,
- "totalHomework" : 25,
- "totalQuiz" : 18,
- "totalScore" : 43
-}
-{
- "_id" : 2,
- "student" : "Ryan",
- "homework" : [ 5, 6, 5 ],
- "quiz" : [ 8, 8 ],
- "extraCredit" : 8,
- "totalHomework" : 16,
- "totalQuiz" : 16,
- "totalScore" : 40
-}
-```
-
-**示例 2:在嵌套记录里增加字段**
-
-可以用点表示法在嵌套记录里增加字段。假设 vehicles 集合含有如下记录:
-```js
-{ _id: 1, type: "car", specs: { doors: 4, wheels: 4 } }
-{ _id: 2, type: "motorcycle", specs: { doors: 0, wheels: 2 } }
-{ _id: 3, type: "jet ski" }
-```
-可以用如下操作在 `specs` 字段下增加一个新的字段 `fuel_type`,值都设为固定字符串 `unleaded`:
-```js
-let res = await db.collection('vehicles').aggregate()
- .addFields({
- 'spec.fuel_type': 'unleaded'
- })
- .end()
-```
-
-返回结果如下:
-```js
-{ _id: 1, type: "car",
- specs: { doors: 4, wheels: 4, fuel_type: "unleaded" } }
-{ _id: 2, type: "motorcycle",
- specs: { doors: 0, wheels: 2, fuel_type: "unleaded" } }
-{ _id: 3, type: "jet ski",
- specs: { fuel_type: "unleaded" } }
-```
-
-**示例 3:设置字段值为另一个字段**
-
-可以通过 `$` 加字段名组成的字符串作为值的表达式来设置字段的值为另一个字段的值。
-
-同样用上一个集合示例,可以用如下操作添加一个字段 `vehicle_type`,将其值设置为 `type` 字段的值:
-```js
-let res = await db.collection('vehicles').aggregate()
- .addFields({
- vehicle_type: '$type'
- })
- .end()
-```
-返回结果如下:
-```js
-{ _id: 1, type: "car", vehicle_type: "car",
- specs: { doors: 4, wheels: 4, fuel_type: "unleaded" } }
-{ _id: 2, type: "motorcycle", vehicle_type: "motorcycle",
- specs: { doors: 0, wheels: 2, fuel_type: "unleaded" } }
-{ _id: 3, type: "jet ski", vehicle_type: "jet ski",
- specs: { fuel_type: "unleaded" } }
-```
-
-### bucket
-
-聚合阶段。将输入记录根据给定的条件和边界划分成不同的组,每组即一个 `bucket`。
-
-**API 说明**
-
-每组分别作为一个记录输出,包含一个以下界为值的 `_id` 字段和一个以组中记录数为值的 `count` 字段。`count` 在没有指定 `output` 的时候是默认输出的。
-
-`bucket` 只会在组内有至少一个记录的时候输出。
-
-**bucket 的形式如下:**
-```js
-bucket({
- groupBy:
,
- boundaries: [, , ...],
- default: ,
- output: {
- : ,
- ...
- :
- }
-})
-```
-`groupBy` 是一个用以决定分组的表达式,会应用在各个输入记录上。可以用 `$` 前缀加上要用以分组的字段路径来作为表达式。除非用 `default` 指定了默认值,否则每个记录都需要包含指定的字段,且字段值必须在 `boundaries` 指定的范围之内。
-
-`boundaries` 是一个数组,每个元素分别是每组的下界。必须至少指定两个边界值。数组值必须是同类型递增的值。
-
-`default` 可选,指定之后,没有进入任何分组的记录将都进入一个默认分组,这个分组记录的 `_id` 即由 `default` 决定。`default` 的值必须小于 `boundaries` 中的最小值或大于等于其中的最大值。`default` 的值可以与 `boundaries` 元素值类型不同。
-
-`output` 可选,用以决定输出记录除了 `_id` 外还要包含哪些字段,各个字段的值必须用累加器表达式指定。当 `output` 指定时,默认的 `count` 是不会被默认输出的,必须手动指定:
-```js
-output: {
- count: $.sum(1),
- ...
- :
-}
-```
-使用 bucket 需要满足以下至少一个条件,否则会抛出错误:
-
-每一个输入记录应用 groupBy 表达式获取的值都必须是一个在 boundaries 内的值
-
-指定一个 default 值,该值在 boundaries 以外,或与 boundaries 元素的值不同的类型。
-
-**示例**
-
-假设集合 items 有如下记录:
-```js
-{
- _id: "1",
- price: 10
-}
-{
- _id: "2",
- price: 50
-}
-{
- _id: "3",
- price: 20
-}
-{
- _id: "4",
- price: 80
-}
-{
- _id: "5",
- price: 200
-}
-```
-
-对上述记录进行分组,将 [0, 50) 分为一组,[50, 100) 分为一组,其他分为一组:
-
-```js
-const $ = db.command.aggregate
-let res = await db.collection('items').aggregate()
- .bucket({
- groupBy: '$price',
- boundaries: [0, 50, 100],
- default: 'other',
- output: {
- count: $.sum(),
- ids: $.push('$_id')
- }
- })
- .end()
-```
-
-返回结果如下:
-
-```js
-[
- {
- "_id": 0,
- "count": 2,
- "ids": [
- "1",
- "3"
- ]
- },
- {
- "_id": 50,
- "count": 2,
- "ids": [
- "2",
- "4"
- ]
- },
- {
- "_id": "other",
- "count": 22,
- "ids": [
- "5"
- ]
- }
-]
-```
-
-### bucketAuto
-
-聚合阶段。将输入记录根据给定的条件划分成不同的组,每组即一个 `bucket`。与 `bucket` 的其中一个不同之处在于无需指定 `boundaries`,`bucketAuto` 会自动尝试将记录尽可能平均的分散到每组中。
-
-**API 说明**
-每组分别作为一个记录输出,包含一个以包含组中最大值和最小值两个字段的对象为值的 _id 字段和一个以组中记录数为值的 count 字段。count 在没有指定 output 的时候是默认输出的。
-
-**bucketAuto 的形式如下:**
-```js
-bucketAuto({
- groupBy: ,
- buckets: ,
- granularity: ,
- output: {
- : ,
- ...
- :
- }
-})
-```
-`groupBy` 是一个用以决定分组的表达式,会应用在各个输入记录上。可以用 $ 前缀加上要用以分组的字段路径来作为表达式。除非用 `default` 指定了默认值,否则每个记录都需要包含指定的字段,且字段值必须在 `boundaries` 指定的范围之内。
-
-`buckets` 是一个用于指定划分组数的正整数。
-
-`granularity` 是可选枚举值字符串,用于保证自动计算出的边界符合给定的规则。这个字段仅可在所有 `groupBy` 值都是数字并且没有 `NaN` 的情况下使用。枚举值包括:`R5、R10、R20、R40、R80、1-2-5、E6、E12、E24、E48、E96、E192、POWERSOF2`。
-
-`output` 可选,用以决定输出记录除了 `_id` 外还要包含哪些字段,各个字段的值必须用累加器表达式指定。当 `output` 指定时,默认的 `count` 是不会被默认输出的,必须手动指定:
-```js
-output: {
- count: $.sum(1),
- ...
- :
-}
-```
-在以下情况中,输出的分组可能会小于给定的组数:
-
-输入记录数少于分组数
-- `groupBy` 计算得到的唯一值少于分组数
-- `granularity` 的间距少于分组数
-- `granularity` 不够精细以至于不能平均分配到各组
-
-**granularity 详细说明**
-
-`granularity` 用于保证边界值属于一个给定的数字序列。
-
-**Renard 序列**
-
-Renard 序列是以 10 的 5 / 10 / 20 / 40 / 80 次方根来推导的、在 1.0 到 10.0 (如果是 R80 则是 10.3) 之间的数字序列。
-
-设置 granularity 为 R5 / R10 / R20 / R40 / R80 就把边界值限定在序列内。如果 groupBy 的值不在 1.0 到 10.0 (如果是 R80 则是 10.3) 内,则序列数字会自动乘以 10。
-
-**E 序列**
-
-E 序列是以 10 的 6 / 12 / 24 / 48 / 96 / 192 次方跟来推导的、带有一个特定误差的、在 1.0 到 10.0 之间的数字序列。
-
-**1-2-5 序列**
-
-1-2-5 序列 表现与三值 Renard 序列一样。
-
-**2的次方序列**
-
-由 2 的各次方组成的序列数字。
-
-**示例**
-
-假设集合 items 有如下记录:
-```js
-{
- _id: "1",
- price: 10.5
-}
-{
- _id: "2",
- price: 50.3
-}
-{
- _id: "3",
- price: 20.8
-}
-{
- _id: "4",
- price: 80.2
-}
-{
- _id: "5",
- price: 200.3
-}
-```
-对上述记录进行自动分组,分成三组:
-```js
-const $ = db.command.aggregate
-let res = await db.collection('items').aggregate()
- .bucket({
- groupBy: '$price',
- buckets: 3,
- })
- .end()
-```
-返回结果如下:
-```js
-{
- "_id": {
- "min": 10.5,
- "max": 50.3
- },
- "count": 2
-}
-{
- "_id": {
- "min": 50.3,
- "max": 200.3
- },
- "count": 2
-}
-{
- "_id": {
- "min": 200.3,
- "max": 200.3
- },
- "count": 1
-}
-```
-
-### count
-
-聚合阶段。计算上一聚合阶段输入到本阶段的记录数,输出一个记录,其中指定字段的值为记录数。
-
-**API 说明**
-
-**count 的形式如下:**
-```js
-count()
-```
- 是输出记录数的字段的名字,不能是空字符串,不能以 $ 开头,不能包含 . 字符。
-
-count 阶段等同于 group + project 的操作:
-```js
-const $ = db.command.aggregate
-let res = await db.collection('items').aggregate()
- .group({
- _id: null,
- count: $.sum(1),
- })
- .project({
- _id: 0,
- })
- .end()
-```
-上述操作会输出一个包含 count 字段的记录。
-
-**示例**
-
-假设集合 items 有如下记录:
-```js
-{
- _id: "1",
- price: 10.5
-}
-{
- _id: "2",
- price: 50.3
-}
-{
- _id: "3",
- price: 20.8
-}
-{
- _id: "4",
- price: 80.2
-}
-{
- _id: "5",
- price: 200.3
-}
-```
-找出价格大于 50 的记录数:
-```js
-const $ = db.command.aggregate
-let res = await db.collection('items').aggregate()
- .match({
- price: $.gt(50)
- })
- .count('expensiveCount')
- .end()
-```
-返回结果如下:
-```js
-{
- "expensiveCount": 3
-}
-```
-
-### geoNear
-
-聚合阶段。将记录按照离给定点从近到远输出。
-
-|属性 |类型 |默认值 |必填 |说明 |
-|---- |---- |---- |---- |---- |
-|near |GeoPoint | |是 |GeoJSON Point,用于判断距离的点 |
-|spherical |true | |是 |必填,值为 true |
-|limit |number | |否 |限制返回记录数 |
-|maxDistance |number | |否 |距离最大值 |
-|minDistance |number | |否 |距离最小值 |
-|query |Object | |否 |要求记录必须同时满足该条件(语法同 where) |
-|distanceMultiplier |number | |否 |返回时在距离上乘以该数字 |
-|distanceField |string | |是 |存放距离的输出字段名,可以用点表示法表示一个嵌套字段 |
-|includeLocs |string | |否 |列出要用于距离计算的字段,如果记录中有多个字段都是地理位置时有用 |
-|key |string | |否 |选择要用的地理位置索引。如果集合由多个地理位置索引,则必须指定一个,指定的方式是指定对应的字段 |
-
-**API 说明**
-
-- `geoNear` 必须为第一个聚合阶段
-- 必须有地理位置索引。如果有多个,必须用 `key` 参数指定要使用的索引。
-
-**示例**
-
-假设集合 attractions 有如下记录:
-```js
-{
- "_id": "geoNear.0",
- "city": "Guangzhou",
- "docType": "geoNear",
- "location": {
- "type": "Point",
- "coordinates": [
- 113.30593,
- 23.1361155
- ]
- },
- "name": "Canton Tower"
-},
-{
- "_id": "geoNear.1",
- "city": "Guangzhou",
- "docType": "geoNear",
- "location": {
- "type": "Point",
- "coordinates": [
- 113.306789,
- 23.1564721
- ]
- },
- "name": "Baiyun Mountain"
-},
-{
- "_id": "geoNear.2",
- "city": "Beijing",
- "docType": "geoNear",
- "location": {
- "type": "Point",
- "coordinates": [
- 116.3949659,
- 39.9163447
- ]
- },
- "name": "The Palace Museum"
-},
-{
- "_id": "geoNear.3",
- "city": "Beijing",
- "docType": "geoNear",
- "location": {
- "type": "Point",
- "coordinates": [
- 116.2328567,
- 40.242373
- ]
- },
- "name": "Great Wall"
-}
-```
-```js
-const $ = db.command.aggregate
-let res = await db.collection('attractions').aggregate()
- .geoNear({
- distanceField: 'distance', // 输出的每个记录中 distance 即是与给定点的距离
- spherical: true,
- near: db.Geo.Point(113.3089506, 23.0968251),
- query: {
- docType: 'geoNear',
- },
- key: 'location', // 若只有 location 一个地理位置索引的字段,则不需填
- includeLocs: 'location', // 若只有 location 一个是地理位置,则不需填
- })
- .end()
-```
-
-返回结果如下:
-```js
-{
- "_id": "geoNear.0",
- "location": {
- "type": "Point",
- "coordinates": [
- 113.30593,
- 23.1361155
- ]
- },
- "docType": "geoNear",
- "name": "Canton Tower",
- "city": "Guangzhou",
- "distance": 4384.68131486958
-},
-{
- "_id": "geoNear.1",
- "city": "Guangzhou",
- "location": {
- "type": "Point",
- "coordinates": [
- 113.306789,
- 23.1564721
- ]
- },
- "docType": "geoNear",
- "name": "Baiyun Mountain",
- "distance": 6643.521654040738
-},
-{
- "_id": "geoNear.2",
- "docType": "geoNear",
- "name": "The Palace Museum",
- "city": "Beijing",
- "location": {
- "coordinates": [
- 116.3949659,
- 39.9163447
- ],
- "type": "Point"
- },
- "distance": 1894750.4414538583
-},
-{
- "_id": "geoNear.3",
- "docType": "geoNear",
- "name": "Great Wall",
- "city": "Beijing",
- "location": {
- "type": "Point",
- "coordinates": [
- 116.2328567,
- 40.242373
- ]
- },
- "distance": 1928300.3308822548
-}
-```
-
-### group
-
-聚合阶段。将输入记录按给定表达式分组,输出时每个记录代表一个分组,每个记录的 _id 是区分不同组的 key。输出记录中也可以包括累计值,将输出字段设为累计值即会从该分组中计算累计值。
-
-
-**API 说明**
-
-**group 的形式如下:**
-```js
-group({
- _id: ,
- : ,
- ...
- :
-})
-```
-
-`_id` 参数是必填的,如果填常量则只有一组。其他字段是可选的,都是累计值,用 `$.sum` 等累计器(`const $ = db.command.aggregate`),但也可以使用其他表达式。
-
-累计器必须是以下操作符之一:
-
-详细使用方法见[累计器操作符](#累计器操作符)
-
-|操作符 |说明 |
-|---- |---- |
-|addToSet |向数组中添加值,如果数组中已存在该值,不执行任何操作 |
-|avg |返回一组集合中,指定字段对应数据的平均值 |
-|sum |计算并且返回一组字段所有数值的总和 |
-|first |返回指定字段在一组集合的第一条记录对应的值。仅当这组集合是按照某种定义排序( sort )后,此操作才有意义。 |
-|last |返回指定字段在一组集合的最后一条记录对应的值。仅当这组集合是按照某种定义排序( sort )后,此操作才有意义。 |
-|max |返回一组数值的最大值 |
-|min |返回一组数值的最小值 |
-|push |在 group 阶段,返回一组中表达式指定列与对应的值,一起组成的数组 |
-|stdDevPop |返回一组字段对应值的标准差 |
-|stdDevSamp |计算输入值的样本标准偏差。如果输入值代表数据总体,或者不概括更多的数据,请改用 db.command.aggregate.stdDevPop|
-|mergeObjects |将多个文档合并为单个文档 |
-
-**内存限制**
-
-该阶段有 100M 内存使用限制。
-
-**示例 1:按字段值分组**
-
-假设集合 avatar 有如下记录:
-```js
-{
- _id: "1",
- alias: "john",
- region: "asia",
- scores: [40, 20, 80],
- coins: 100
-}
-{
- _id: "2",
- alias: "arthur",
- region: "europe",
- scores: [60, 90],
- coins: 20
-}
-{
- _id: "3",
- alias: "george",
- region: "europe",
- scores: [50, 70, 90],
- coins: 50
-}
-{
- _id: "4",
- alias: "john",
- region: "asia",
- scores: [30, 60, 100, 90],
- coins: 40
-}
-{
- _id: "5",
- alias: "george",
- region: "europe",
- scores: [20],
- coins: 60
-}
-{
- _id: "6",
- alias: "john",
- region: "asia",
- scores: [40, 80, 70],
- coins: 120
-}
-```
-```js
-const $ = db.command.aggregate
-let res = await db.collection('avatar').aggregate()
- .group({
- _id: '$alias',
- num: $.sum(1)
- })
- .end()
-```
-返回结果如下:
-```js
-{
- "_id": "john",
- "num": 3
-}
-{
- "_id": "authur",
- "num": 1
-}
-{
- "_id": "george",
- "num": 2
-}
-```
-
-**示例 2:按多个值分组**
-
-可以给 _id 传入记录的方式按多个值分组。还是沿用上面的示例数据,按各个区域(region)获得相同最高分(score)的来分组,并求出各组虚拟币(coins)的总量:
-```js
-const $ = db.command.aggregate
-let res = await db.collection('avatar').aggregate()
- .group({
- _id: {
- region: '$region',
- maxScore: $.max('$scores')
- },
- totalCoins: $.sum('$coins')
- })
- .end()
-```
-返回结果如下:
-```js
-{
- "_id": {
- "region": "asia",
- "maxScore": 80
- },
- "totalCoins": 220
-}
-{
- "_id": {
- "region": "asia",
- "maxScore": 100
- },
- "totalCoins": 100
-}
-{
- "_id": {
- "region": "europe",
- "maxScore": 90
- },
- "totalCoins": 70
-}
-{
- "_id": {
- "region": "europe",
- "maxScore": 20
- },
- "totalCoins": 60
-}
-```
-
-### limit
-
-聚合阶段。限制输出到下一阶段的记录数。
-
-**示例**
-
-假设集合 items 有如下记录:
-```js
-{
- _id: "1",
- price: 10
-}
-{
- _id: "2",
- price: 50
-}
-{
- _id: "3",
- price: 20
-}
-{
- _id: "4",
- price: 80
-}
-{
- _id: "5",
- price: 200
-}
-```
-返回价格大于 20 的记录的最小的两个记录:
-```js
-const $ = db.command.aggregate
-let res = await db.collection('items').aggregate()
- .match({
- price: $.gt(20)
- })
- .sort({
- price: 1,
- })
- .limit(2)
- .end()
-```
-返回结果如下:
-```js
-{
- "_id": "3",
- "price": 20
-}
-{
- "_id": "4",
- "price": 80
-}
-```
-
-### lookup
-
-聚合阶段。联表查询。与同个数据库下的一个指定的集合做 left outer join(左外连接)。对该阶段的每一个输入记录,lookup 会在该记录中增加一个数组字段,该数组是被联表中满足匹配条件的记录列表。lookup 会将连接后的结果输出给下个阶段。
-
-**API 说明**
-
-`lookup` 有两种使用方式
-
-#### 相等匹配
-将输入记录的一个字段和被连接集合的一个字段进行相等匹配时,采用以下定义:
-```js
-lookup({
- from: <要连接的集合名>,
- localField: <输入记录的要进行相等匹配的字段>,
- foreignField: <被连接集合的要进行相等匹配的字段>,
- as: <输出的数组字段名>
-})
-```
-
-**参数详细说明**
-
-|参数字段 |说明 |
-|---- |---- |
-|from |要进行连接的另外一个集合的名字 |
-|localField |当前流水线的输入记录的字段名,该字段将被用于与 from 指定的集合的 foreignField 进行相等匹配。如果输入记录中没有该字段,则该字段的值在匹配时会被视作 null|
-|foreignField |被连接集合的字段名,该字段会被用于与 localField 进行相等匹配。如果被连接集合的记录中没有该字段,该字段的值将在匹配时被视作 null |
-|as |指定连接匹配出的记录列表要存放的字段名,这个数组包含的是匹配出的来自 from 集合的记录。如果输入记录中本来就已有该字段,则该字段会被覆写 |
-
-这个操作等价于以下伪 SQL 操作:
-
-```
-SELECT *,