# 云数据库操作符@dbcmd

## 查询·逻辑操作符@dbcmd-query

### and

查询操作符，用于表示逻辑 "与" 的关系，表示需同时满足多个查询筛选条件  

#### 使用说明
 `and` 有两种使用情况：  

 

**1. 用在根查询条件**

 此时需传入多个查询条件，表示需同时满足提供的多个完整查询条件  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where(dbCmd.and([
  {
    progress: dbCmd.gt(50)
  },
  {
    tags: 'cloud'
  }
])).get()
```
但以上用 `and` 组成的查询条件是不必要的，因为传入的对象的各字段隐式组成了 “与” 的关系，上述条件等价于下方更简洁的写法：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.gt(50),
  tags: 'cloud'
}).get()
```

通常需要显示使用 `and` 是用在有跨字段或操作的时候


**2. 用在字段查询条件**

 需传入多个查询操作符或常量，表示字段需满足或匹配给定的条件。  

 如以下用前置写法的方式表示 "progress 字段值大于 50 且小于 100"  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.and(dbCmd.gt(50), dbCmd.lt(100))
}).get()
```
还可以用后置写法的方式表示同样的条件：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.gt(50).and(dbCmd.lt(100))
}).get()
```
注意 `Command` 默认也可以直接链式调用其他 `Command`，默认表示多个 `Command` 的与操作，因此上述代码还可以精简为：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.gt(50).lt(100)
}).get()
```

#### 调用风格
 方法接收两种传参方式，一是传入一个数组参数，二是传入多个参数，效果一样。  

 
```js
// 传入数组
function and(expressions: Expression[]): Command
// 传入多参数
function and(...expressions: Expression[]): Command
```

### or

查询操作符，用于表示逻辑 "或" 的关系，表示需同时满足多个查询筛选条件。或指令有两种用法，一是可以进行字段值的 “或” 操作，二是也可以进行跨字段的 “或” 操作。  

     
#### 字段值的或操作
 字段值的 “或” 操作指的是指定一个字段值为多个值之一即可。  

 如筛选出进度大于 80 或小于 20 的 todo：  

 流式写法：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.gt(80).or(dbCmd.lt(20))
}).get()
```
前置写法：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.or(dbCmd.gt(80), dbCmd.lt(20))
}).get()
```
前置写法也可接收一个数组：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.or([dbCmd.gt(80), dbCmd.lt(20)])
}).get()
```

#### 跨字段的或操作
 跨字段的 “或” 操作指条件 “或”，相当于可以传入多个 where 语句，满足其中一个即可。  

 如筛选出进度大于 80 或已标为已完成的 todo：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where(dbCmd.or([
  {
    progress: dbCmd.gt(80)
  },
  {
    done: true
  }
])).get()
```

#### 调用风格
 方法接收两种传参方式，一是传入一个数组参数，二是传入多个参数，效果一样。  

 
```js
// 传入数组
function or(expressions: Expression[]): Command
// 传入多参数
function or(...expressions: Expression[]): Command
```

### not

查询操作符，用于表示逻辑 "非" 的关系，表示需不满足指定的条件。  

     
#### 示例
 如筛选出进度不等于100的 todo：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.not(dbCmd.eq(100))
}).get()
```
`not` 也可搭配其他逻辑指令使用，包括 `and`, `or`, `nor`, `not`，如 `or`：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.not(dbCmd.or([dbCmd.lt(50), dbCmd.eq(100)]))
}).get()
```

### nor

查询操作符，用于表示逻辑 "都不" 的关系，表示需不满足指定的所有条件。如果记录中没有对应的字段，则默认满足条件。  

     
#### 示例 1
 筛选出进度既不小于20又不大于80的 todo ：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.nor([dbCmd.lt(20), dbCmd.gt(80)])
}).get()
```
以上同时会筛选出不存在 `progress` 字段的记录，如果要要求 `progress` 字段存在，可以用 `exists` 指令：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where({
  progress: dbCmd.exists().nor([dbCmd.lt(20), dbCmd.gt(80)])
  // 等价于以下非链式调用的写法：
  // progress: dbCmd.exists().and(dbCmd.nor([dbCmd.lt(20), dbCmd.gt(80)]))
}).get()
```

#### 示例 2
 筛选出 `progress` 不小于 20 且 `tags` 数组不包含 `miniprogram` 字符串的记录：  

 
```js
const dbCmd = db.command
db.collection('todo').where(dbCmd.nor([{
  progress: dbCmd.lt(20),
}, {
  tags: 'miniprogram',
}])).get()
```
以上会筛选出满足以下条件之一的记录：  

 
1. `progress` 不小于 20 且 `tags` 数组不包含 `miniprogram` 字符串 3. `progress` 不小于 20 且 `tags` 字段不存在 5. `progress` 字段不存在 且 `tags` 数组不包含 `miniprogram` 字符串 7. `progress` 不小于 20 且 `tags` 字段不存在
 如果要求 `progress` 和 `tags` 字段存在，可以用 `exists` 指令：  

 
```js
const dbCmd = db.command
let res = await db.collection('todo').where(
  dbCmd.nor([{
    progress: dbCmd.lt(20),
  }, {
    tags: 'miniprogram',
  }])
  .and({
    progress: dbCmd.exists(true),
    tags: dbCmd.exists(true),
  })
).get()
```

#### 调用风格
 方法接收两种传参方式，一是传入一个数组参数，二是传入多个参数，效果一样。  

 
```js
// 传入数组
function nor(expressions: Expression[]): Command
// 传入多参数
function nor(...expressions: Expression[]): Command
```

## 查询·比较操作符@dbcmd-compare

### eq

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

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

 
```js
const openID = 'xxx'
let res = await db.collection('articles').where({
  _openid: openID
}).get()
```
还可以用指令：  

 
```js
const dbCmd = db.command
const openID = '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

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

     
#### 使用说明
 表示字段不等于某个值，和 [eq](Command.eq.html) 相反

### lt

查询筛选操作符，表示需小于指定值。可以传入 `Date` 对象用于进行日期比较。  

     
#### 示例代码
 找出进度小于 50 的 todo  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.lt(50)
})
.get()
```

### lte

查询筛选操作符，表示需小于或等于指定值。可以传入 `Date` 对象用于进行日期比较。  

     
#### 示例代码
 找出进度小于或等于 50 的 todo  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.lte(50)
})
.get()
```

### gt

查询筛选操作符，表示需大于指定值。可以传入 `Date` 对象用于进行日期比较。  

     
#### 示例代码
 找出进度大于 50 的 todo  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.gt(50)
})
.get()
```

### gte

查询筛选操作符，表示需大于或等于指定值。可以传入 `Date` 对象用于进行日期比较。  

     
#### 示例代码
 找出进度大于或等于 50 的 todo  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.gte(50)
})
.get()
```

### in

查询筛选操作符，表示要求值在给定的数组内。  

     
#### 示例代码
 找出进度为 0 或 100 的 todo  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.in([0, 100])
})
.get()
```

### nin

查询筛选操作符，表示要求值不在给定的数组内。  

     
#### 示例代码
 找出进度不是 0 或 100 的 todo  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.nin([0, 100])
})
.get()
```

## 查询·字段操作符@dbcmd-field

### exists

判断字段是否存在  

     
#### 示例代码
 找出存在 tags 字段的记录  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  tags: dbCmd.exists(true)
})
.get()
```

### mod

查询筛选操作符，给定除数 divisor 和余数 remainder，要求字段作为被除数时 value % divisor = remainder。  

      
#### 示例代码
 找出进度为 10 的倍数的字段的记录  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  progress: dbCmd.mod(10, 0)
})
.get()
```

## 查询·数组操作符@dbcmd-array

### all

数组查询操作符。用于数组字段的查询筛选条件，要求数组字段中包含给定数组的所有元素。  

     
#### 示例代码 1：普通数组
 找出 tags 数组字段同时包含 cloud 和 database 的记录  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  tags: dbCmd.all(['cloud', 'database'])
})
.get()
```

#### 示例代码 2：对象数组
 如果数组元素是对象，则可以用 `dbCmd.elemMatch` 匹配对象的部分字段  

 假设有字段 `places` 定义如下：  

 
```js
{
  "type": string
  "area": number
  "age": number
}
```
找出数组字段中至少同时包含一个满足 “area 大于 100 且 age 小于 2” 的元素和一个满足 “type 为 mall 且 age 大于 5” 的元素  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  places: dbCmd.all([
    dbCmd.elemMatch({
      area: dbCmd.gt(100),
      age: dbCmd.lt(2),
    }),
    dbCmd.elemMatch({
      type: 'mall',
      age: dbCmd.gt(5),
    }),
  ]),
})
.get()
```

### elemMatch

用于数组字段的查询筛选条件，要求数组中包含至少一个满足 `elemMatch` 给定的所有条件的元素  

      
#### 示例代码：数组是对象数组的情况
 假设集合示例数据如下：  

 
```js
{
  "_id": "a0",
  "city": "x0",
  "places": [{
    "type": "garden",
    "area": 300,
    "age": 1
  }, {
    "type": "theatre",
    "area": 50,
    "age": 15
  }]
}
```
找出 `places` 数组字段中至少同时包含一个满足 “area 大于 100 且 age 小于 2” 的元素  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  places: dbCmd.elemMatch({
    area: dbCmd.gt(100),
    age: dbCmd.lt(2),
  })
})
.get()
```
*注意**：如果不使用 `elemMatch` 而直接如下指定条件，则表示的是 `places` 数组字段中至少有一个元素的 `area` 字段大于 100 且 `places` 数组字段中至少有一个元素的 `age` 字段小于 2：  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  places: {
    area: dbCmd.gt(100),
    age: dbCmd.lt(2),
  }
})
.get()
```

#### 示例代码：数组元素都是普通数据类型的情况
 假设集合示例数据如下：  

 
```js
{
  "_id": "a0",
  "scores": [60, 80, 90]
}
```
找出 `scores` 数组字段中至少同时包含一个满足 “大于 80 且小于 100” 的元素  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  scores: dbCmd.elemMatch(dbCmd.gt(80).lt(100))
})
.get()
```

### size

更新操作符，用于数组字段的查询筛选条件，要求数组长度为给定值  

     
#### 示例
 找出 tags 数组字段长度为 2 的所有记录  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').where({
  places: dbCmd.size(2)
})
.get()
```

## 查询·地理位置操作符@dbcmd-geo

### geoNear

按从近到远的顺序，找出字段值在给定点的附近的记录。  

     
#### 索引要求
 需对查询字段建立地理位置索引  

 
#### 示例代码
 找出离给定位置 1 公里到 5 公里范围内的记录  

 
```js
const dbCmd = db.command
let res = await db.collection('restaurants').where({
  location: dbCmd.geoNear({
    geometry: new db.Geo.Point(113.323809, 23.097732),
    minDistance: 1000,
    maxDistance: 5000,
  })
}).get()
```

### geoWithin

找出字段值在指定区域内的记录，无排序。指定的区域必须是多边形（Polygon）或多边形集合（MultiPolygon）。  

     
#### 索引要求
 需对查询字段建立地理位置索引  

 
#### 示例代码 1：给定多边形
 
```js
const dbCmd = db.command
const { Point, LineString, Polygon } = db.Geo
let res = await .collection('restaurants').where({
  location: dbCmd.geoWithin({
    geometry: new Polygon([
      new LineString([
        new Point(0, 0),
        new Point(3, 2),
        new Point(2, 3),
        new Point(0, 0)
      ])
    ]),
  })
}).get()
```

#### 示例代码 2：给定圆形
 可以不用 `geometry` 而用 `centerSphere` 构建一个圆形。  

  `centerSphere` 对应的值的定义是：`[ [经度, 纬度], 半径 ]`  

 半径需以弧度计，比如需要 10km 的半径，则用距离除以地球半径 6378.1km 得出的数字。  

 
```js
const dbCmd = db.command
let res = await db.collection('restaurants').where({
  location: dbCmd.geoWithin({
    centerSphere: [
      [-88, 30],
      10 / 6378.1,
    ]
  })
}).get()
```

### geoIntersects

找出给定的地理位置图形相交的记录  

     
#### 索引要求
 需对查询字段建立地理位置索引  

 
#### 示例代码：找出和一个多边形相交的记录
 
```js
const dbCmd = db.command
const { Point, LineString, Polygon } = db.Geo
let res = await db.collection('restaurants').where({
  location: dbCmd.geoIntersects({
    geometry: new Polygon([
      new LineString([
        new Point(0, 0),
        new Point(3, 2),
        new Point(2, 3),
        new Point(0, 0)
      ])
    ]),
  })
}).get()
```

## 查询·表达式操作符@dbcmd-expr

### expr

查询操作符，用于在查询语句中使用聚合表达式，方法接收一个参数，该参数必须为聚合表达式  
      
#### 使用说明
 
1. `expr` 可用于在聚合 [`match`](cf-database-aggregate#aggregate-match) 流水线阶段中引入聚合表达式 3. 如果聚合 [`match`](cf-database-aggregate#aggregate-match) 阶段是在 [`lookup`](cf-database-aggregate#aggregate-lookup) 阶段内，此时的 `expr` 表达式内可使用 `lookup` 中使用 `let` 参数定义的变量，具体示例可见 [`lookup`](cf-database-aggregate#aggregate-lookup) 的 `指定多个连接条件` 例子 5. `expr` 可用在普通查询语句（`where`）中引入聚合表达式
 
#### 示例代码 1：比较同一个记录中的两个字段
 假设 `items` 集合的数据结构如下：  

 
```js
{
  "_id": string,
  "inStock": number, // 库存量
  "ordered": number  // 被订量
}
```
找出被订量大于库存量的记录：  

 
```js
const dbCmd = db.command
const $ = dbCmd.aggregate
let res = await db.collection('items').where(dbCmd.expr($.gt(['$ordered', '$inStock']))).get()
```

#### 示例代码 2：与条件语句组合使用
 假设 `items` 集合的数据结构如下：  

 
```json
{
  "_id": string,
  "price": number
}
```
假设价格小于等于 10 的打 8 折，大于 10 的打 5 折，让数据库查询返回打折后价格小于等于 8 的记录：  

 
```js
const dbCmd = db.command
const $ = dbCmd.aggregate
let res = await db.collection('items').where(dbCmd.expr(
  $.lt([
    $.cond({
      if: $.gte(['$price', 10]),
      then: $.multiply(['$price', '0.5']),
      else: $.multiply(['$price', '0.8']),
    })
    ,
    8
  ])
).get()
```

## 更新·字段操作符@dbcmd-update-field

### set

更新操作符，用于设定字段等于指定值。  

     
#### 使用说明
 这种方法相比传入纯 JS 对象的好处是能够指定字段等于一个对象  

 
#### 示例
 
```js
// 以下方法只会更新 style.color 为 red，而不是将 style 更新为 { color: 'red' }，即不影响 style 中的其他字段
let res = await db.collection('todos').doc('doc-id').update({
  style: {
    color: 'red'
  }
})

// 以下方法更新 style 为 { color: 'red', size: 'large' }
let res = await db.collection('todos').doc('doc-id').update({
  style: dbCmd.set({
    color: 'red',
    size: 'large'
  })
})
```

### remove

更新操作符，用于表示删除某个字段。  

   
#### 示例代码
 删除 style 字段：  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('todo-id').update({
  style: dbCmd.remove()
})
```

### inc

更新操作符，原子操作，用于指示字段自增  

      
#### 原子自增
 多个用户同时写，对数据库来说都是将字段自增，不会有后来者覆写前者的情况  

 
#### 示例代码
 将一个 todo 的进度自增 10：  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('todo-id').update({
  progress: dbCmd.inc(10)
})
```

### mul

更新操作符，原子操作，用于指示字段自乘某个值  

      
#### 原子自乘
 多个用户同时写，对数据库来说都是将字段自乘，不会有后来者覆写前者的情况  

 
#### 示例代码
 将一个 todo 的进度自乘 10：  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('todo-id').update({
  progress: dbCmd.mul(10)
})
```

### min

更新操作符，给定一个值，只有该值小于字段当前值才进行更新。  

     
#### 示例代码
 如果字段 progress > 50，则更新到 50  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  progress: dbCmd.min(50)
})
```

### max

更新操作符，给定一个值，只有该值大于字段当前值才进行更新。  

     
#### 示例代码
 如果字段 progress < 50，则更新到 50  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  progress: dbCmd.max(50)
})
```

### rename

更新操作符，字段重命名。如果需要对嵌套深层的字段做重命名，需要用点路径表示法。不能对嵌套在数组里的对象的字段进行重命名。  

     
#### 示例 1：重命名顶层字段
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  progress: dbCmd.rename('totalProgress')
})
```

#### 示例 2：重命名嵌套字段
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  someObject: {
    someField: dbCmd.rename('someObject.renamedField')
  }
})
```

或：
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  'someObject.someField': dbCmd.rename('someObject.renamedField')
})
```

## 更新·数组操作符@dbcmd-update-array

### push

数组更新操作符。对一个值为数组的字段，往数组添加一个或多个值。或字段原为空，则创建该字段并设数组为传入值。  

     
#### 参数说明
 

**position 说明**

 要求必须同时有 `each` 参数存在。  

 非负数代表从数组开始位置数的位置，从 0 开始计。如果数值大于等于数组长度，则视为在尾部添加。负数代表从数组尾部倒数的位置，比如 -1 就代表倒数第二个元素的位置。如果负数数值的绝对值大于等于数组长度，则视为从数组头部添加。  

 

**sort 说明**

 要求必须同时有 `each` 参数存在。给定 1 代表升序，-1 代表降序。  

 如果数组元素是记录，则用 `{ <字段>: 1 | -1 }` 的格式表示根据记录中的什么字段做升降序排序。  

 

**slice** 说明**

 要求必须同时有 `each` 参数存在  

|值		|说明									|
|:-:	|:-:									|
|0		|将字段更新为空数组		|
|正数	|数组只保留前 n 个元素|
|负数	|数组只保留后 n 个元素|


#### 示例 1：尾部添加元素
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push(['mini-program', 'cloud'])
})
```

#### 示例 2：从第二个位置开始插入
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push({
    each: ['mini-program', 'cloud'],
    position: 1,
  })
})
```

#### 示例 3：排序

插入后对整个数组做排序  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push({
    each: ['mini-program', 'cloud'],
    sort: 1,
  })
})
```

不插入，只对数组做排序  
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push({
    each: [],
    sort: 1,
  })
})
```
如果字段是对象数组，可以如下根据元素对象里的字段进行排序：  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push({
    each: [
      { name: 'miniprogram', weight: 8 },
      { name: 'cloud', weight: 6 },
    ],
    sort: {
      weight: 1,
    },
  })
})
```

#### 示例 4：截断保留
 插入后只保留后 2 个元素  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push({
    each: ['mini-program', 'cloud'],
    slice: -2,
  })
})
```

#### 示例 5：在指定位置插入、然后排序、最后只保留前 2 个元素
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.push({
    each: ['mini-program', 'cloud'],
    position: 1,
    slice: 2,
    sort: 1,
  })
})
```

### pop

数组更新操作符，对一个值为数组的字段，将数组尾部元素删除，仅可以删除末尾一个

#### 示例代码
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.pop()
})
```

### unshift

数组更新操作符，对一个值为数组的字段，往数组头部添加一个或多个值。或字段原为空，则创建该字段并设数组为传入值。  

     
#### 示例代码
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.unshift(['mini-program', 'cloud'])
})
```

### shift

数组更新操作符，对一个值为数组的字段，将数组头部元素删除。  

   
#### 示例代码
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.shift()
})
```

### pull

数组更新操作符。给定一个值或一个查询条件，将数组中所有匹配给定值或查询条件的元素都移除掉。  

#### 示例代码 1：根据常量匹配移除
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.pull('database')
})
```

#### 示例代码 2：根据查询条件匹配移除
 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.pull(dbCmd.in(['database', 'cloud']))
})
```

#### 示例代码 3：对象数组时，根据查询条件匹配移除
 假设有字段 `places` 数组中的元素结构如下  

 
```json
{
  "type": string
  "area": number
  "age": number
}
```

```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  places: dbCmd.pull({
    area: dbCmd.gt(100),
    age: dbCmd.lt(2),
  })
})
```

#### 示例代码 4：有嵌套对象的对象数组时，根据查询条件匹配移除
 假设有字段 `cities` 数组中的元素结构如下  

 
```js
{
  "name": string
  "places": Place[]
}
```
`Place` 结构如下：  

 
```js
{
  "type": string
  "area": number
  "age": number
}
```
可用 `elemMatch` 匹配嵌套在对象数组里面的对象数组字段 places  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  cities: dbCmd.pull({
    places: dbCmd.elemMatch({
      area: dbCmd.gt(100),
      age: dbCmd.lt(2),
    })
  })
})
```

### pullAll

数组更新操作符。给定一个值或一个查询条件，将数组中所有匹配给定值的元素都移除掉。跟 `pull` 的差别在于只能指定常量值、传入的是数组。  

      
#### 示例代码：根据常量匹配移除
 从 tags 中移除所有 database 和 cloud 字符串  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.pullAll(['database', 'cloud'])
})
```

### addToSet

数组更新操作符。原子操作。给定一个或多个元素，除非数组中已存在该元素，否则添加进数组。  

      
#### 示例代码 1：添加一个元素
 如果 tags 数组中不包含 database，添加进去  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.addToSet('database')
})
```

#### 示例代码 2：添加多个元素

需传入一个对象，其中有一个字段 `each`，其值为数组，每个元素就是要添加的元素  

 
```js
const dbCmd = db.command
let res = await db.collection('todos').doc('doc-id').update({
  tags: dbCmd.addToSet({
    $each: ['database', 'cloud']
  })
})
```
