# API

## 基础概念

### 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 |

## 获取数据库实例

说明：不需要参数，返回数据库的实例

```js
// 初始化
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
```

## 获取集合的引用

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

```js
// 获取 `user` 集合的引用
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})

const db = app.database()

const collection = db.collection('user')
```

## 查询指令

### eq

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

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const myOpenID = 'xxx'
    const res = await db
        .collection('articles')
        .where({
            _openid: myOpenID
        })
        .get()

    console.log(res.data) // 打印查询的文档数组

    // 用指令的方式
    const res1 = await db
        .collection('articles')
        .where({
            _openid: _.eq(myOpenID)
        })
        .get()

    console.log(res1.data) // 打印查询的文档数组
}
```

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    // 这种写法表示匹配 stat.publishYear == 2018 且 stat.language == 'zh-CN'
    const res = await db
        .collection('articles')
        .where({
            stat: {
                publishYear: 2018,
                language: 'zh-CN'
            }
        })
        .get()

    console.log(res.data) // 打印查询的文档数组

    // 这种写法表示 stat 对象等于 { publishYear: 2018, language: 'zh-CN' }
    const res1 = await db
        .collection('articles')
        .where({
            stat: _.eq({
                publishYear: 2018,
                language: 'zh-CN'
            })
        })
        .get()

    console.log(res1.data) // 打印查询的文档数组
}
```

### neq

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

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                brand: _.neq('X')
            }
        })
        .get()

    console.log(res.data) // 打印查询的文档数组
}
```

### gt

字段大于指定值。

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            price: _.gt(2000)
        })
        .get()

    console.log(res.data) // 打印查询的文档数组
}
```

### gte

字段大于或等于指定值。

### lt

字段小于指定值。

### lte

字段小于或等于指定值。

### in

字段值在给定的数组中。

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: _.in([8, 16])
            }
        })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

### nin

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

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: _.nin([8, 16])
            }
        })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

### and

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

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    // 流式写法
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: _.gt(4).and(_.lt(32))
            }
        })
        .get()

    console.log(res.data) // 打印查询的文档数组

    // 前置写法
    const res1 = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: _.and(_.gt(4), _.lt(32))
            }
        })
        .get()

    console.log(res1.data) // 打印查询的文档数组
}
```

### or

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    //流式写法：
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                price: _.lt(4000).or(_.gt(6000).and(_.lt(8000)))
            }
        })
        .get()
    console.log(res.data) // 打印查询的文档数组

    // 前置写法
    const res1 = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                price: _.or(_.lt(4000), _.and(_.gt(6000), _.lt(8000)))
            }
        })
        .get()

    console.log(res1.data) // 打印查询的文档数组

    // 如果要跨字段 “或” 操作：(如筛选出内存 8g 或 cpu 3.2 ghz 的计算机)
    const res2 = await db
        .collection('goods')
        .where(
            _.or(
                {
                    type: {
                        memory: _.gt(8)
                    }
                },
                {
                    type: {
                        cpu: 3.2
                    }
                }
            )
        )
        .get()

    console.log(res2.data) // 打印查询的文档数组
}
```

### RegExp

根据正则表达式进行筛选

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk');
const app = tcb.init({
  env:'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
  // 可以直接使用正则表达式
  const res = await db.collection('articles').where({
    version: /^\ds/i
  }).get()

  console.log(res.data) // 打印查询的文档数组

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

  console.log(res1.data) // 打印查询的文档数组
}
```

## 更新指令

### set

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

示例代码：

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('photo')
        .doc('doc-id')
        .update({
            data: {
                style: _.set({
                    color: 'red',
                    size: 'large'
                })
            }
        })
    console.log(res.updated) // 打印更新成功的文档数量
}
```

### inc

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

备注：

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

之后的 mul 指令同理。

示例代码：

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('user')
        .where({
            _openid: 'my-open-id'
        })
        .update({
            count: {
                favorites: _.inc(1)
            }
        })
    console.log(res.updated) // 打印更新成功的文档数量
}
```

### mul

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

### remove

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('comments')
        .doc('comment-id')
        .update({
            rating: _.remove()
        })
    console.log(res.updated) // 打印更新成功的文档数量
}
```

### push

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('comments')
        .doc('comment-id')
        .update({
            // users: _.push('aaa')
            users: _.push(['aaa', 'bbb'])
        })
    console.log(res.updated) // 打印更新成功的文档数量
}
```

### pop

删除数组尾部元素

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('comments')
        .doc('comment-id')
        .update({
            users: _.pop()
        })
    console.log(res.updated) // 打印更新成功的文档数量
}
```

### unshift

向数组头部添加元素，支持传入单个元素或数组。使用同 push

### shift

删除数组头部元素。使用同 pop

## 构建查询条件

支持 `where()`、`limit()`、`skip()`、`orderBy()`、`get()`、`update()`、`field()`、`count()` 等操作。

只有当调用`get()`、 `update()`时才会真正发送请求。

### where

描述：设置过滤条件。where 可接收对象作为参数，表示筛选出拥有和传入对象相同的 key-value 的文档。

输入参数： 无

比如筛选出所有类型为计算机的、内存为 8g 的商品：

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})

const db = app.database()

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: 8
            }
        })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

如果要表达更复杂的查询，可使用高级查询指令，比如筛选出所有内存大于 8g 的计算机商品：

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk');
const app = tcb.init({
  env:'xxx'
})

const db = app.database();

const _ = db.command // 取指令

exports.main = async (event, context) => {
  const res = await db.collection('goods').where({
    category: 'computer',
    type: {
      memory: _.gt(8), // 表示大于 8
    }
  }).get()
  console.log(res.data) // 打印查询的文档数组
```

### limit

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

输入参数：

| 参数 | 类型    | 必填 | 说明           |
| ---- | ------- | ---- | -------------- |
| -    | Integer | 是   | 限制展示的数值 |

使用示例

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const collection = db.collection('user') // 例 操作 user 集合

exports.main = async (event, context) => {
    const res = await collection
        .where({})
        .limit(1)
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

### skip

描述：指定查询返回结果时从指定序列后的结果开始返回，常用于分页
输入参数：

| 参数 | 类型    | 必填 | 说明           |
| ---- | ------- | ---- | -------------- |
| -    | Integer | 是   | 限制展示的数值 |

示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const collection = db.collection('user') // 例 操作 user 集合

exports.main = async (event, context) => {
    const res = await collection
        .where({})
        .skip(4)
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

### field

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

输入参数：

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

示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const collection = db.collection('user') // 例 操作 user 集合

exports.main = async (event, context) => {
    const res = await collection
        .where({})
        .field({ age: true })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

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

### orderBy

描述：指定查询排序条件

输入参数：

| 参数      | 类型   | 必填 | 说明                                |
| --------- | ------ | ---- | ----------------------------------- |
| field     | String | 是   | 排序的字段                          |
| orderType | String | 是   | 排序的顺序，升序(asc) 或 降序(desc) |

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

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

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

示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const collection = db.collection('user') // 例 操作 user 集合

exports.main = async (event, context) => {
    const res = await collection
        .where({})
        .orderBy('name', 'asc')
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

### options

描述：数据库接口配置

输入参数：

| 参数     | 类型    | 必填 | 说明                                       |
| -------- | ------- | ---- | ------------------------------------------ |
| timeout  | Number  | 否   | SDK 请求超时时间设置, 默认 15000ms         |
| multiple | Boolean | 否   | 是否仅操作单个文档，update/delete 方法可用 |

示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const collection = db.collection('user') // 例 操作 user 集合

exports.main = async (event, context) => {
    // 更新单文档
    const updateRes = await collection
        .where({ name: 'luke' })
        .options({ multiple: false })
        .update({
            name: 'lake'
        })

    console.log(res.updated === 1) // 更新文档数为1

    // 删除单文档
    const deleteRes = await collection
        .where({ name: 'luke' })
        .options({ multiple: false })
        .remove()

    console.log(res.deleted === 1) // 删除文档数为1

    // 设置SDK单接口请求超时
    const getRes = await collection
        .where({ name: 'luke' })
        .options({ timeout: 10000 })
        .get()
    console.log(getRes)
}
```

## createCollection

#### 1. 接口描述

接口功能：新增集合

接口声明：`createCollection(collName): Promise<Object>`

#### 2. 输入参数

| 参数 | 类型   | 必填 | 说明   |
| ---- | ------ | ---- | ------ |
| -    | String | 是   | 集合名 |

#### 3. 返回结果

| 字段      | 类型   | 必填 | 说明                 |
| --------- | ------ | ---- | -------------------- |
| requestId | String | 是   | 请求 ID              |
| message   | String | 否   | 接口报错时的错误信息 |
| code      | String | 否   | 接口报错时的错误码   |

#### 4. 示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})

const db = app.database()

exports.main = async (event, context) => {
    // 创建集合名为coll-name的集合
    const res = await db.createCollection('coll-name')

    if (!res.code) {
        // 创建成功
    }
}
```

## add

#### 1. 接口描述

接口功能：插入一条文档或文档数组

接口声明：`collection.add(object: Array<Object> | Object): Promise<Object>`

备注：set 方法也可以用来新增文档，请参看文档更新部分 [set](#update-set) 方法

#### 2. 输入参数

| 参数 | 类型                      | 必填 | 说明                                                                                                                                                |
| ---- | ------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| -    | `Array<Object> or Object` | 是   | 可支持批量插入或插入单个文档，例 [{\_id: '10001', 'name': 'Ben'}, {\_id: '10002', 'name': 'Booker'}] 或 {\_id: '10001', 'name': 'Ben'}, \_id 非必填 |

#### 3. 返回结果

| 字段      | 类型            | 必填 | 说明                            |
| --------- | --------------- | ---- | ------------------------------- |
| code      | String          | 否   | 状态码，操作成功则不返回        |
| message   | String          | 否   | 错误描述，操作成功不返回        |
| requestId | String          | 是   | 请求 ID                         |
| id        | String          | 否   | 文档 ID，插入单文档成功则返回   |
| ids       | `Array<String>` | 否   | 文档 ID，批量插入文档成功则返回 |

#### 4. 示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})

const db = app.database()
const collection = db.collection('user') // 例 操作 user 集合

exports.main = async (event, context) => {
    // 创建集合名为coll-name的集合
    const res = await collection.add({
        name: 'Ben'
    })

    console.log(res.id) //打印新增的文档ID

    const batchRes = await collection.add([{ name: 'luke' }, { name: 'jimmy' }])
    console.log(batchRes.ids)
}
```

## get

#### 1. 接口描述

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

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

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

#### 2. 输入参数

空

#### 3. 返回结果

| 字段      | 类型   | 必填 | 说明                     |
| --------- | ------ | ---- | ------------------------ |
| code      | string | 否   | 状态码，操作成功则不返回 |
| message   | string | 否   | 错误描述                 |
| data      | Object | 否   | 操作成功返回查询结果     |
| requestId | string | 是   | 请求序列号，用于错误排查 |

#### 4. 示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: 8
            }
        })
        .count()
    console.log(res.data) // 打印查询的文档数组
}
```

## count

#### 1. 接口描述

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

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

#### 2. 输入参数

空

#### 3. 返回结果

| 字段      | 类型    | 必填 | 说明                     |
| --------- | ------- | ---- | ------------------------ |
| code      | string  | 否   | 状态码，操作成功则不返回 |
| message   | string  | 否   | 错误描述                 |
| total     | integer | 否   | 计数结果                 |
| requestId | string  | 否   | 请求序列号，用于错误排查 |

#### 4. 示例代码

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const res = await db
        .collection('goods')
        .where({
            category: 'computer',
            type: {
                memory: 8
            }
        })
        .count()
    console.log(res.total) // 打印查询的文档数量
}
```

## remove

#### 1. 接口描述

接口功能：删除一条文档

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

#### 2. 输入参数

无

#### 3. 返回结果

| 字段      | 类型    | 必填 | 说明                     |
| --------- | ------- | ---- | ------------------------ |
| code      | string  | 否   | 状态码，操作成功则不返回 |
| message   | string  | 否   | 错误描述                 |
| deleted   | integer | 否   | 删除的文档数量           |
| requestId | string  | 是   | 请求序列号，用于错误排查 |

#### 4. 示例代码

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

collection.doc(\_id).remove()

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const res = await db
        .collection('articles')
        .doc('xxx')
        .remove()

    console.log(res.deleted) // 打印删除的文档数量
}
```

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    // 删除字段a的值大于2的文档
    const res = await db
        .collection('articles')
        .where({
            a: _.gt(2)
        })
        .remove()

    console.log(res.deleted) // 打印删除的文档数量
}
```

## update / set

#### 1. 接口描述

接口功能：更新文档

接口声明：

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

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

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

#### 2. 输入参数

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

#### 3. 返回结果

| 字段       | 类型    | 必填 | 说明                     |
| ---------- | ------- | ---- | ------------------------ |
| code       | string  | 否   | 状态码，操作成功则不返回 |
| message    | string  | 否   | 错误描述                 |
| updated    | integer | 否   | 影响的文档数量           |
| upsertedId | string  | 否   | 插入的文档的 id          |
| requestId  | string  | 是   | 请求序列号，用于错误排查 |

#### 4. 示例代码

更新指定文档

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    // 更新单文档
    const res = await db
        .collection('articles')
        .doc('doc-id')
        .update({
            name: 'Hey'
        })

    console.log(res.updated) // 打印更新成功的文档数量

    // 批量更新文档
    const res1 = await db
        .collection('articles')
        .where({ name: _.eq('hey') })
        .update({
            age: 18
        })

    console.log(res1.updated) // 打印更新成功的文档数量
}
```

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

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    // 更新单文档
    const res = await db
        .collection('articles')
        .doc('doc-id')
        .set({
            name: 'Hey'
        })
    console.log(res.upsertedId) // 打印插入的文档的id
}
```

## 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
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    const res = await db
        .collection('user')
        .where({
            location: db.command.geoNear({
                geometry: new db.Geo.Point(lngA, latA),
                maxDistance: 1000,
                minDistance: 0
            })
        })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

#### geoWithin

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

签名：

```js
db.command.geoWithin(IOptions)

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

示例：

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    // 一个闭合的区域
    const area = new Polygon([
        new LineString([
            new Point(lngA, latA),
            new Point(lngB, latB),
            new Point(lngC, latC),
            new Point(lngA, latA)
        ])
    ])

    // 搜索 location 字段在这个区域中的 user
    const res = await db
        .collection('user')
        .where({
            location: db.command.geoWithin({
                geometry: area
            })
        })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

#### geoIntersects

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

签名：

```js
db.command.geoIntersects(IOptions)

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

示例：

```js
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()
const _ = db.command

exports.main = async (event, context) => {
    // 一条路径
    const line = new LineString([new Point(lngA, latA), new Point(lngB, latB)])

    // 搜索 location 与这条路径相交的 user
    const res = await db
        .collection('user')
        .where({
            location: db.command.geoIntersects({
                geometry: line
            })
        })
        .get()
    console.log(res.data) // 打印查询的文档数组
}
```

## 时间 Date

Date 类型用于表示时间，精确到毫秒，可以用 JavaScript 内置 Date 对象创建。需要特别注意的是，用此方法创建的时间是客户端时间，不是服务端时间。如果需要使用服务端时间，应该用 API 中提供的 serverDate 对象来创建一个服务端当前时间的标记，当使用了 serverDate 对象的请求抵达服务端处理时，该字段会被转换成服务端当前的时间，更棒的是，我们在构造 serverDate 对象时还可通过传入一个有 offset 字段的对象来标记一个与当前服务端时间偏移 offset 毫秒的时间，这样我们就可以达到比如如下效果：指定一个字段为服务端时间往后一个小时。

那么当我们需要使用客户端时间时，存放 Date 对象和存放毫秒数是否是一样的效果呢？不是的，我们的数据库有针对日期类型的优化，建议大家使用时都用 Date 或 serverDate 构造时间对象。

```js
//服务端当前时间
new db.serverDate()
```

```js
//服务端当前时间加1S
new db.serverDate({
    offset: 1000
})
```

## 数据库事务

### startTransaction

#### 1. 接口描述

接口功能：发起事务

接口声明：`startTransaction(): Promise<Object>`

#### 2. 输入参数

无

#### 3. 返回结果

| 参数    | 类型   | 必填 | 说明                     |
| ------- | ------ | ---- | ------------------------ |
| \_id    | string | 否   | 成功则返回事务 id        |
| code    | string | 否   | 状态码，操作成功则不返回 |
| message | string | 否   | 错误描述                 |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const transaction = await db.startTransaction()
    console.log(transaction._id) // 打印事务id
}
```

### commit

#### 1. 接口描述

接口功能：提交事务

接口声明：`commit(): Promise<Object>`

#### 2. 输入参数

无

#### 3. 返回结果

| 字段      | 类型   | 必填 | 说明                        |
| --------- | ------ | ---- | --------------------------- |
| requestId | string | 是   | 请求 id                     |
| code      | string | 否   | 状态码，操作成功则不返回    |
| message   | string | 否   | 错误描述， 操作成功则不返回 |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const transaction = await db.startTransaction()
    await transaction.commit()
}
```

### get

#### 1. 接口描述

接口功能：事务查询文档

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

#### 2. 输入参数

无

#### 3. 返回结果

| 参数      | 类型                 | 必填 | 说明                        |
| --------- | -------------------- | ---- | --------------------------- |
| data      | &lt;Array&gt;.Object | 否   | 操作成功，返回文档对象数组  |
| requestId | string               | 是   | 请求 id                     |
| code      | string               | 否   | 状态码，操作成功则不返回    |
| message   | string               | 否   | 错误描述， 操作成功则不返回 |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    /**
     * 事务操作支持两种写法，写法一如下，1. 调用startTransaction发起事务 2. 事务操作 3.调用commitTransactio提交事务
     *
     *
     */
    const transaction = await db.startTransaction()
    const doc = await transaction
        .collection(collectionName)
        .doc('docId')
        .get()
    console.log(doc.data) // 打印查询的文档
    await transaction.commit()

    /**
     * 写法二，runTransaction(callback(transaction)), 支持用户传入回调，回调参数为transaction
     *
     *
     */
    await db.runTransaction(async function(transaction) {
        const doc = await transaction
            .collection(collectionName)
            .doc('docId')
            .get()
        console.log(doc.data) // 打印查询的文档
    })
}
```

### add

#### 1. 接口描述

接口功能：事务插入文档

接口声明：`add(data): Promise<Object>`

#### 2. 输入参数

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

#### 3. 返回结果

| 参数      | 类型   | 必填 | 说明                        |
| --------- | ------ | ---- | --------------------------- |
| requestId | string | 是   | 请求 id                     |
| code      | string | 否   | 状态码，操作成功则不返回    |
| message   | string | 否   | 错误描述， 操作成功则不返回 |
| id        | string | 否   | 插入数据的 docId            |
| inserted  | number | 否   | 插入成功的条数              |
| ok        | number | 否   | 插入状态 1 表示成功         |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    // 云函数环境下，下面代码放置入口函数体内
    const transaction = await db.startTransaction()
    const res = await transaction
        .collection(collectionName)
        .add({ category: 'Web', tags: ['JavaScript', 'C#'], date })
    console.log(res.id) // 打印添加的docId
    await transaction.commit()
}
```

### update / set

#### 1. 接口描述

接口功能：事务更新文档

接口声明：

`update(data): Promise<Object>`

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

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

#### 2. 输入参数

| 参数 | 类型   | 必填 | 说明             |
| ---- | ------ | ---- | ---------------- |
| -    | Object | 是   | 要更新的字段对象 |

#### 3. 返回结果

| 参数      | 类型   | 必填 | 说明                        |
| --------- | ------ | ---- | --------------------------- |
| updated   | number | 否   | 更新成功的条数              |
| upserted  | number | 否   | 插入成功的条数              |
| requestId | string | 是   | 请求 id                     |
| code      | string | 否   | 状态码，操作成功则不返回    |
| message   | string | 否   | 错误描述， 操作成功则不返回 |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const transaction = await db.startTransaction()
    // update
    const updateResult = await transaction
        .collection(collectionName)
        .doc('docId')
        .update({
            category: 'Node.js',
            date
        })

    console.log(updateResult.updated) // 更新的条数

    // set
    const setResult = await transaction
        .collection(collectionName)
        .doc('docId')
        .set({
            category: 'Node.js',
            date
        })

    console.log(setResult.updated, setResult.upserted)
    await transaction.commit()
}
```

### delete

#### 1. 接口描述

接口功能：事务删除文档

接口声明：`delete(): Promise<Object>`

#### 2. 输入参数

无

#### 3. 返回结果

| 字段      | 类型   | 必填 | 说明                        |
| --------- | ------ | ---- | --------------------------- |
| deleted   | number | 否   | 删除成功的条数              |
| requestId | string | 是   | 请求 id                     |
| code      | string | 否   | 状态码，操作成功则不返回    |
| message   | string | 否   | 错误描述， 操作成功则不返回 |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    // deletaDocument
    const transaction = await db.startTransaction()
    const deleteResult = await transaction
        .collection(collectionName)
        .doc('docId')
        .delete()
    console.log(deleteResult.deleted) // 删除成功的条数
    await transaction.commit()
}
```

### rollback

#### 1. 接口描述

接口功能：事务回滚

接口声明：`rollback(): Promise<Object>`

#### 2. 输入参数

无

#### 3. 返回结果

| 字段      | 类型   | 必填 | 说明    |
| --------- | ------ | ---- | ------- |
| requestId | string | 是   | 请求 id |

#### 4. 示例代码

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    // 云函数环境下，下面代码放置入口函数体内
    const transaction = await db.startTransaction()
    const doc = await transaction
        .collection(collectionName)
        .doc('docId')
        .get()
    console.log(doc.data)
    await transaction.rollback()
    await transaction.commit()
}
```

### runTransaction 使用说明

1. 支持自定义返回 (正常 return 或 throw error)

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    const result = await db.runTransaction(async function(transaction) {
        const doc = await transaction
            .collection(collectionName)
            .doc('1')
            .get()
        console.log(doc.data)
        return 'luke'
    })
}

// result === 'luke'
```

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    try {
        await db.runTransaction(async transaction => {
            const doc = await transaction
                .collection(collectionName)
                .doc('1')
                .get()
            console.log(doc.data)
            // mock 事务冲突
            throw {
                code: 'DATABASE_TRANSACTION_CONFLICT',
                message:
                    '[ResourceUnavailable.TransactionConflict] Transaction is conflict, maybe resource operated by others. Please check your request, but if the problem persists, contact us.'
            }
        })
    } catch (e) {
        // e.code === 'DATABASE_TRANSACTION_CONFLICT'
    }
}
```

2. rollback 使用

```javascript
// 云函数环境下示例代码
const tcb = require('@cloudbase/node-sdk')
const app = tcb.init({
    env: 'xxx'
})
const db = app.database()

exports.main = async (event, context) => {
    try {
        await db.runTransaction(async function(transaction) {
            const doc = await transaction
                .collection(collectionName)
                .doc('1')
                .get()
            console.log(doc.data)
            await transaction.rollback('luke')
        })
    } catch (err) {
        // err === 'luke'
    }

    try {
        await db.runTransaction(async function(transaction) {
            const doc = await transaction
                .collection(collectionName)
                .doc('1')
                .get()
            console.log(doc.data)
            await transaction.rollback()
        })
    } catch (err) {
        // assert(err.requestId)
        console.log(err.requestId) // 默认rollback返回回滚的requestId
    }
}
```
