Collection

集合实例

doc

支持端:小程序,小游戏。
获取集合中指定记录的引用。方法接受一个 id 参数,指定需引用的记录的 _id。

参数

id: string
记录 _id

返回值

document

示例语法

const todo = db.collection('todos').doc('id').get();

错误说明

docId 传入空字符串时。

错误语法1

const todo = db.collection('todos').doc('').get();

错误信息

{ errorCode: 156401, errMsg: 'docId必须为非空字符串', }

构建查询条件

where

支持端:小程序,小游戏。
指定查询条件,返回带新查询条件的新的集合引用

参数

condition: Object
查询条件

返回值

collection

示例语法

const res = await db.collection('todos').where({ age: 10 }).get();

错误说明

错误语法1
try { const res = await db.collection('todos').where(1 as any).get(); } catch (error) { console.log(error); }
错误信息
{ errorCode: '156401', errMsg: '查询参数必须为对象' }
错误语法2
try { const res = await db.collection('todos').where({ age: undefined }).get(); } catch (error) { console.log(error); }
错误信息
{ errorCode: '156401', errMsg: '查询参数对象值不能均为undefined' }
错误语法3
var b: any = { } var a = { b: b } b.a = a; try{ const res = await db.collection("todos").where(a).get(); }catch(err) { console.log(err); }
错误信息
{ errorCode: '156401', errMsg: '不能将循环结构转换为JSON' }

limit

支持端:小程序,小游戏。
指定查询结果数量上限。

参数

value: number

返回值

collection

示例语法

const res = await db.collection('todos').limit(1).get();

错误说明

错误语法1
try { const res = await db.collection('todos').limit('1' as any).get(); } catch (error) { console.log(error); }
返回错误
{ errorCode: 156401, errMsg: 'limit 必须是一个整型' }

orderBy

支持端:小程序,小游戏。
方法接受一个必填字符串参数 fieldName 用于定义需要排序的字段,一个字符串参数 order 定义排序顺序。order 只能取 ascdesc
如果需要对嵌套字段排序,需要用 "点表示法" 连接嵌套字段,比如 style.color 表示字段 style 里的嵌套字段 color
同时也支持按多个字段排序,多次调用 orderBy 即可,多字段排序时的顺序会按照 orderBy 调用顺序先后对多个字段排序。

参数

{ fieldPath: string, order: string }

返回值

Collection

示例语法

升序查询
const res = await db.collection('todos').orderBy('age', 'asc').get();
降序查询
const res = await db.collection('todos').orderBy('age', 'desc').get();
嵌套升序查询
const res = await db.collection('todos').orderBy('person.age', 'asc').get();
嵌套降序查询
const res = await db.collection('todos').orderBy('person.age', 'desc').get();

错误说明

错误语法1
try { const res = await db.collection('todos').orderBy('^', 'desc').get(); } catch (error) { console.log(error); }
错误信息
{ errorCode: 156401, errMsg: '非法排序路径' }
错误语法2
try { const res = await db.collection('todos').orderBy('a', 1 as any).get(); } catch (error) { console.log(error); }
错误错误
{ errorCode: 156401, errMsg: '排序字符不合法' // 必须为desc或者asc }

field

支持端:小程序,小游戏。
指定返回结果中记录需返回的字段,方法接受一个必填对象用于指定需返回的字段,对象的各个 key 表示要返回或不要返回的字段,value 传入 true|false(或 1|-1)表示要返回还是不要返回。

参数

projection: Object

示例语法

const res = await db.collection('todos').field({ age: true }).get();

错误说明

错误语法1
const res = await db.collection('todos').field({ age: [1] }).get();
错误信息
{ errorCode: 156401, errMsg: 'field参数对象值必须是一个对象,整型或者布尔值' }

skip

支持端:小程序,小游戏。
指定查询返回结果时从指定序列后的结果开始返回,常用于分页。

参数

value: number

返回值

collection

示例语法

const res = await db.collection('todos').skip(1).get();

错误说明

错误语法1
const res = await db.collection('todos').skip('123' as any).get()
错误信息
{ errorCode: 156401, errMsg: 'skip 必须是一个整型' }

请求

get

支持端:小程序,小游戏。
获取集合数据,或获取根据查询条件筛选后的集合数据
本次版本暂时都只支持promise 语法,不支持回调。

示例语法

const res = await db.collection("todos").get();

返回值

{ data: [ { name _id: "6436bdf4e5120202e27f9ac1", name: 'mike' } ], requestId: '' }

update

支持端:小程序,小游戏。
更新多条记录。

示例语法

const res = await db.collection('todos').where({ age: 1 }).update({ age: 2 });

返回值

{ updated 1 requestId: "" }

错误说明

错误语法1
try { const res = await db.collection('todos').where({ age: 1 }).update({ _id: 1 }); } catch (error) { console.log(error) }
错误信息
{ errorCode: 156401 errMsg: ‘_id值不能更新’ }
错误语法2
try { await db.collection('todos').where({ age: 1 }).update({}); } catch (error) { console.log(error); }
错误信息
{ errorCode: 156401 errMsg: '参数必须为非空对象' }

remove

支持端:小程序,小游戏。
删除多条记录。注意只支持通过匹配 where 语句来删除,不支持 skiplimit

示例语法

const res = await db.collection("todos").where({name:"ckq"}).remove();

返回值

{ deleted: 0, requestId:'' }

错误说明

错误语法1
const res = await db.collection('todos').skip(1).remove();
错误信息
{ errCode: 156401, errMsg: 'remove()操作不支持skip,limit,projection,orderBy', }

count

支持端:小程序,小游戏。
统计匹配查询条件的记录的条数。

示例语法

const res = await db.collection('todos').count();

返回值

{ total: 3, requestid:'' }

add

支持端:小程序,小游戏。
新增记录,如果传入的记录对象没有 _id 字段,则由后台自动生成 _id;若指定了 _id,则不能与已有记录冲突。

示例语法

const res = await db.collection("todos").add({ "name": "mike" })

返回值

{ id: "6436b6fee5120202e27f9ab7" requestId: "" }

错误说明

错误语法1
const res = await db.collection("todos").add("" as any);
返回错误
{ errorCode: 156401, errMsg: "参数必须是对象" }

聚合

发起聚合操作,定义完聚合流水线阶段之后需调用 end 方法标志结束定义并实际发起聚合操作。

限制

聚合阶段有 32M 内存使用限制。

聚合示例

const $ = db.command.aggregate const res = db.collection('books') .aggregate() .group({// 按 category 字段分组 _id: '$category',// 让输出的每组记录有一个 avgSales 字段,其值是组内所有记录的 sales 字段的平均值 avgSales: $.avg('$sales') }) .end();

addFields

支持端:小程序,小游戏。
聚合阶段。添加新字段到输出的记录。经过 addFields 聚合阶段,输出的所有记录中除了输入时带有的字段外,还将带有 addFields 指定的字段。

参数

object: Object

返回值

Aggregate

API 说明

addFields 等同于同时指定了所有已有字段和新增字段的 project 阶段。
addFields 的形式如下:
addFields({ <新字段>: <表达式> })
addFields 可指定多个新字段,每个新字段的值由使用的表达式决定。
如果指定的新字段与原有字段重名,则新字段的值会覆盖原有字段的值。注意 addFields 不能用来给数组字段添加元素。

示例1:连续两次addFields

假设有如下记录:
{ "_id": "xxx", "homework": [ 1, 2, 3], "quiz": [4, 5, 6] }
应用两次 addFields,第一次增加两个字段分别为 homeworkquiz 的和值,第二次增加一个字段再基于上两个和值求一次和值。
const $ = db.command.aggregate; const res = await db .collection('aggregate_db') .aggregate() .addFields({ totalHomework: $.sum('$homework'), totalQuiz: $.sum('$quiz') }) .addFields({ totolScore: $.add(['$totalHomework', '$totalQuiz']) }) .end();
返回结果如下:
{ "_id": "xxx", "homework": [ 1, 2, 3], "quiz": [4, 5, 6 ], "totalHomework": 6, "totalQuiz": 15, "totolScore": 21 }

示例2:在嵌套记录里增加字段

假设有如下记录:
{ "_id": "xxx", "person": { "age": 10, "name": "demo" } } { "_id": "xxx", "person": { "age": 10, "name": "demo1" } }
可以用如下操作在 person 字段下增加一个新的字段 sex,值都设为固定字符串 male:
const res = await db .collection('aggregate_db') .aggregate() .addFields({ 'person.sex': 'male' }) .end();
返回结果如下:
{ "_id": "xxx", "person": [ { "name": "demo1", "age": 10, "sex": "male" } ] } { "_id": "xxx", "person": { "name": "demo", "age": 10, "sex": "male" } }

示例3:设置字段值为另一个字段

假设有如下记录:
{ "_id": "xxx", "age": 10, "name": "demo" } { "_id": "xxx", "age": 10, "name": "demo1" }
可以通过 $ 加字段名组成的字符串作为值的表达式来设置字段的值为另一个字段的值。
同样用上一个集合示例,可以用如下操作添加一个字段 second_name,将其值设置为 name 字段的值:
const res = await db .collection('aggregate_db') .aggregate() .addFields({ second_name: '$name' }) .end();
返回结果如下:
{ "_id": "xxx", "name": "demo", "age": 10, "second_name": "demo" } { "_id": "xxx", "name": "demo1", "age": 10 }

错误语法

await db.collection('dbcommand_error_todos').aggregate().addFields(1).end();

错误信息

{ "errCode": 156401, "errMsg": "addFields 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 addFields 语句 const res = await db .collection('aggregate_db') .aggregate() .addFields({ second_name: '$name' }) .end(); }

bucket

支持端:小程序,小游戏。
聚合阶段。将输入记录根据给定的条件和边界划分成不同的组,每组即一个 bucket

参数

object: Object

返回值

Aggregate

API 说明

每组分别作为一个记录输出,包含一个以下界为值的 _id 字段和一个以组中记录数为值的 count 字段。count 在没有指定 output 的时候是默认输出的。
bucket 只会在组内有至少一个记录的时候输出。
bucket 的形式如下:
bucket({ groupBy: <expression>, boundaries: [<lowerbound1>, <lowerbound2>, ...], default: <literal>, output: { <output1>: <accumulator expr>, ... <outputN>: <accumulator expr> } })
groupBy 是一个用以决定分组的表达式,会应用在各个输入记录上。可以用 $ 前缀加上要用以分组的字段路径来作为表达式。除非用 default 指定了默认值,否则每个记录都需要包含指定的字段,且字段值必须在 boundaries 指定的范围之内。
boundaries 是一个数组,每个元素分别是每组的下界。必须至少指定两个边界值。数组值必须是同类型递增的值。
default 可选,指定之后,没有进入任何分组的记录将都进入一个默认分组,这个分组记录的 _id 即由 default 决定。default 的值必须小于 boundaries 中的最小值或大于等于其中的最大值。default 的值可以与 boundaries 元素值类型不同。
output 可选,用以决定输出记录除了 _id 外还要包含哪些字段,各个字段的值必须用累加器表达式指定。当 output 指定时,默认的 count 是不会被默认输出的,必须手动指定:
output: { count: $.sum(1), ... <outputN>: <accumulator expr> }
使用 bucket 需要满足以下至少一个条件,否则会抛出错误:
    每一个输入记录应用 groupBy 表达式获取的值都必须是一个在 boundaries 内的值
    指定一个 default 值,该值在 boundaries 以外,或与 boundaries 元素的值不同的类型。

示例

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "age": 10, "name": "demo1" } { "_id": "xxx", "age": 50, "name": "demo2" } { "_id": "xxx", "age": 20, "name": "demo3" } { "_id": "xxx", "age": 80, "name": "demo4" } { "_id": "xxx", "age": 200, "name": "demo5" }
对上述记录进行分组,将 [0, 50) 分为一组,[50, 100) 分为一组,其他分为一组:
const $ = db.command.aggregate; const res = await db .collection('aggregate_db') .aggregate() .bucket({ groupBy: '$age', boundaries: [0, 50, 100], default: 'other', output: { count: $.sum(1), names: $.push('$name'), }, }) .end();
返回结果如下:
[ { "_id": 0, "count": 2, "names": [ "demo1", "demo3"] }, { "_id": 50, "count": 2, "names": [ "demo2", "demo4" ] }, { "_id": "other", "count": 1, "names": [ "demo5" ] } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().bucket(1).end();

错误信息

{ "errCode": 156401, "errMsg": "bucket 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 bucket 语句 const $ = db.command.aggregate; const res = await db .collection('aggregate_db') .aggregate() .bucket({ groupBy: '$age', boundaries: [0, 50, 100], default: 'other', output: { count: $.sum(1), names: $.push('$name'), }, }) .end(); }

bucketAuto

支持端:小程序,小游戏。
聚合阶段。将输入记录根据给定的条件划分成不同的组,每组即一个 bucket。与 bucket 的其中一个不同之处在于无需指定 boundariesbucketAuto 会自动尝试将记录尽可能平均的分散到每组中。

参数

object: Object

返回值

Aggregate

API 说明

每组分别作为一个记录输出,包含一个以包含组中最大值和最小值两个字段的对象为值的 _id 字段和一个以组中记录数为值的 count 字段。count 在没有指定 output 的时候是默认输出的。
bucketAuto 的形式如下:
bucketAuto({ groupBy: <expression>, buckets: <number>, granularity: <string>, output: { <output1>: <accumulator expr>, ... <outputN>: <accumulator expr> } })
groupBy 是一个用以决定分组的表达式,会应用在各个输入记录上。可以用 $ 前缀加上要用以分组的字段路径来作为表达式。除非用 default 指定了默认值,否则每个记录都需要包含指定的字段,且字段值必须在 boundaries 指定的范围之内。
buckets 是一个用于指定划分组数的正整数。
granularity 是可选枚举值字符串,用于保证自动计算出的边界符合给定的规则。这个字段仅可在所有 groupBy 值都是数字并且没有 NaN 的情况下使用。枚举值包括:R5R10R20R40R801-2-5E6E12E24E48E96E192POWERSOF2
output 可选,用以决定输出记录除了 _id 外还要包含哪些字段,各个字段的值必须用累加器表达式指定。当 output 指定时,默认的 count 是不会被默认输出的,必须手动指定:
output: { count: $.sum(1), ... <outputN>: <accumulator expr> }
在以下情况中,输出的分组可能会小于给定的组数:
    输入记录数少于分组数
    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 的各次方组成的序列数字。

示例

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "name": "demo1", "price": 10.5 } { "_id": "xxx", "name": "demo2", "price": 50.3 } { "_id": "xxx", "name": "demo3", "price": 20.8 } { "_id": "xxx", "name": "demo4", "price": 80.2 } { "_id": "xxx", "name": "demo5", "price": 200.3 }
对上述记录进行自动分组,分成三组:
const res = await db .collection('aggregate_db') .aggregate() .bucketAuto({ groupBy: '$price', buckets: 3, output: { count: db.command.aggregate.sum(1), names: db.command.aggregate.push('$name'), }, }) .end();
返回结果如下:
[ { "_id":{ "min": 10.5, "max": 50.3 }, "count":2, "names": [ "demo1", "demo3"]}, { "_id":{ "min": 50.3, "max": 200.3 }, "count":2, "names": ["demo2","demo4"]}, { "_id":{"min": 200.3,"max": 200.3 }, "count":1, "names": ["demo5"] } ]

错误语法

await db .collection('dbcommand_error_todos') .aggregate() .bucketAuto(1) .end();

错误信息

{ "errCode": 156401, "errMsg": "bucketAuto 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际bucketAuto语句 const res = await db .collection('aggregate_db') .aggregate() .bucketAuto({ groupBy: '$price', buckets: 3, output: { count: db.command.aggregate.sum(1), names: db.command.aggregate.push('$name'), }, }) .end(); }

count

支持端:小程序,小游戏。
聚合阶段。计算上一聚合阶段输入到本阶段的记录数,输出一个记录,其中指定字段的值为记录数。

参数

fieldName: string

返回值

Aggregate

API 说明

count 的形式如下:
count(<string>)
<string> 是输出记录数的字段的名字,不能是空字符串,不能以 $ 开头,不能包含 . 字符。

示例:

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "name": "demo", "price": 10.5 } { "_id": "xxx", "name": "demo", "price": 50.3 } { "_id": "xxx", "name": "demo", "price": 20.8 }
找出价格大于 50 的记录数。
const res = await db .collection('aggregate_db') .aggregate() .match({ price: db.command.gt(50), }) .count('expensiveCount') .end();
返回结果如下:
[ { "expensiveCount": 3 } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().count(3).end();

错误信息

{ "errCode": 156401, "errMsg": "count 值必须是一个字符串" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 count 语句 const res = await db .collection('aggregate_db') .aggregate() .match({ price: db.command.gt(50), }) .count('expensiveCount') .end(); }

group

支持端:小程序,小游戏。
聚合阶段。将输入记录按给定表达式分组,输出时每个记录代表一个分组,每个记录的 _id 是区分不同组的 key。输出记录中也可以包括累计值,将输出字段设为累计值即会从该分组中计算累计值。

参数

object: Object

返回值

Aggregate

API 说明

group 的形式如下:
group({ _id: <expression>, <field1>: <accumulator1>, ... <fieldN>: <accumulatorN> })
_id 参数是必填的,如果填常量则只有一组。其他字段是可选的,都是累计值,用 $.sum 等累计器,但也可以使用其他表达式。
累计器必须是以下操作符之一:
addToSet | avg | first | last | max | min | push | sum
内存限制
该阶段有 100M 内存使用限制。

示例1:按字段值分组

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "age": 1, "name": "demo" }{ "_id": "xxx", "age": 1, "name": "demo" }{ "_id": "xxx", "age": 1, "name": "demo2" }{ "_id": "xxx", "age": 1, "name": "demo3" }{ "_id": "xxx", "age": 1, "name": "demo3" }
const res = await db .collection('aggregate_db') .aggregate() .group({ _id: '$name', num: db.command.aggregate.sum(1), }) .end();
返回结果如下:
[ {"_id": "demo3", "num": 2 }, {"_id": "demo2", "num": 1 }, {"_id": "demo", "num": 2 } ]

示例2:按多个值分组

假设集合 aggregate_db 有如下记录:
{ "alias": "john", "coins": 100, "region": "asia", "scores": [40, 20, 80] } { "alias": "arthur", "coins": 20, "region": "europe", "scores": [60, 90] } { "alias": "george", "region": "europe", "scores": [50, 70, 90], "coins": 50 } { "alias": "john", "region": "asia", "scores": [30, 60, 100, 90], "coins": 40 } { "alias": "george", "region": "europe", "scores": [20], "coins": 60 } { "alias": "john", "region": "asia", "scores": [40, 80, 70], "coins": 120 }
可以给 _id 传入记录的方式按多个值分组。
const $ = db.command.aggregate; const res = await db .collection('aggregate_db') .aggregate() .group({ _id: { region: '$region', maxScore: $.max('$scores'), }, totalCoins: $.sum('$coins'), }) .end();
返回结果如下:
[ { "_id": { "region": "europe", "maxScore": 20 }, "totalCoins": 60 }, { "_id": { "region": "asia", "maxScore": 100 }, "totalCoins": 40 }, { "_id": { "region": "europe", "maxScore": 90 }, "totalCoins": 70 }, { "_id": { "region": "asia", "maxScore": 80 }, "totalCoins": 220 } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().group(3).end();

错误信息

{ "errCode": 156401, "errMsg": "group 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 group 语句 const res = await db .collection('aggregate_db') .aggregate() .group({ _id: { region: '$region', maxScore: $.max('$scores'), }, totalCoins: $.sum('$coins'), }) .end(); }

limit

支持端:小程序,小游戏。
聚合阶段。限制输出到下一阶段的记录数。

参数

value: number
正整数

限制

limit 上限为 10000 条。

返回值

Aggregate

示例:

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "name": "demo", "price": 10 } { "_id": "xxx", "name": "demo", "price": 50 } { "_id": "xxx", "name": "demo", "price": 20 } { "_id": "xxx", "name": "demo", "price": 80 } { "_id": "xxx", "name": "demo", "price": 200 }
返回价格大于 20 的记录的最小的两个记录:
const res = await db .collection('aggregate_db') .aggregate() .match({ price: db.command.gt(20) }) .limit(2) .end();
返回结果如下:
[ { "_id": "xxx", "name": "demo", "price": 50 }, { "_id": "xxx", "name": "demo", "price": 80 } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().limit('4').end();

错误信息

{ "errCode": 156401, "errMsg": "limit 值必须是一个整型" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际limit语句 const res = await db .collection('aggregate_db') .aggregate() .match({ price: db.command.gt(20) }) .limit(2) .end(); }

match

支持端:小程序,小游戏。
聚合阶段。根据条件过滤文档,并且把符合条件的文档传递给下一个流水线阶段。

参数

object: Object

返回值

Aggregate

API 说明

match 的形式如下:
match(<查询条件>)
查询条件与普通查询一致,可以用普通查询操作符,注意 match 阶段和其他聚合阶段不同,不可使用聚合操作符,只能使用查询操作符。
// 直接使用字符串 match({ name: 'Tony Stark' }) //使用操作符 const _ = db.command match({ age: _.gt(18) })

示例1:匹配

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "author": "stark", "id": 1, "score": 80 } { "_id": "xxx", "author": "stark", "id": 2, "score": 85 } { "_id": "xxx", "author": "bob", "id": 3, "score": 60 }
下面是一个直接匹配的例子,这里的代码尝试找到所有 author 字段是 stark 的文章,那么匹配如下
const res = await db .collection('aggregate_db') .aggregate() .match({ author: 'stark', }) .end();
返回结果如下:
[ { "_id": "xxx", "id": 1, "author": "stark", "score": 80 }, { "_id": "xxx", "id": 2, "author": "stark", "score": 85 } ]

示例2:计数

match 过滤出文档后,还可以与其他流水线阶段配合使用。
假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "author": "stark", "id": 1, "score": 80 } { "_id": "xxx", "author": "stark", "id": 2, "score": 85 } { "_id": "xxx", "author": "bob", "id": 3, "score": 60 }
比如下面这个例子,我们使用 group 进行搭配,计算 score 字段大于 80 的文档数量:
const _ = db.command; const $ = _.aggregate; const countRes = await db .collection('aggregate_db') .aggregate() .match({ score: _.gt(80), }) .group({ _id: null, count: $.sum(1), }) .end();
返回结果如下:
[ { "_id": null, "count": 1 } ]

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 match 语句 const res = await db .collection('aggregate_db') .aggregate() .match({ author: 'stark', }) .end(); }

project

支持端:小程序,小游戏。
聚合阶段。把指定的字段传递给下一个流水线,指定的字段可以是某个已经存在的字段,也可以是计算出来的新字段。

参数

object: Object

返回值

Aggregate

API 说明

project 的形式如下:
project({ <表达式> })
表达式可以有以下格式:
格式
说明
<字段>: <1 或 true>
指定包含某个已有字段
_id: <0 或 false>
舍弃 _id 字段
<字段>: <表达式>
加入一个新字段,或者重置某个已有字段
<字段>: <0 或 false>
舍弃某个字段(如果你指定舍弃了某个非 _id 字段,那么在此次 project 中,你不能再使用其它表达式)
指定包含字段
_id 字段是默认包含在输出中的,除此之外其他任何字段,如果想要在输出中体现的话,必须在 project 中指定; 如果指定包含一个尚不存在的字段,那么 project 会忽略这个字段,不会加入到输出的文档中;
指定排除字段
如果你在 project 中指定排除某个字段,那么其它字段都会体现在输出中; 如果指定排除的是非 _id 字段,那么在本次 project 中,不能再使用其它表达式;
加入新的字段或重置某个已有字段
你可以使用一些特殊的表达式加入新的字段,或重置某个已有字段。
多层嵌套的字段
有时有些字段处于多层嵌套的底层,我们可以使用点记法
"contact.phone.number": <1 or 0 or 表达式>
也可以直接使用嵌套的格式:
contact: { phone: { number: <1 or 0 or 表达式> } }

示例1:指定包含某些字段

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "title": "This is title", "author": "Nobody", "isbn": "123456789", "introduction": "......", "scores": { "chinese": 80, "math": 90, "english": 70 } }
下面的代码使用 project,让输出只包含 _idtitleauthor 字段
const res = await db .collection('aggregate_db') .aggregate() .project({ title: 1, author: 1, }) .end();
返回结果如下:
[ { "_id": "xxx", "title": "This is title", "author": "Nobody" } ]

示例2:去除输出中的 _id 字段

集合沿用示例1
_id 是默认包含在输出中的,如果不想要它,可以指定去除它:
const res = await db .collection('aggregate_db') .aggregate() .project({ _id: 0, // 指定去除 _id 字段 title: 1, author: 1, }) .end();
返回结果如下:
[ { "title": "This is title", "author": "Nobody" } ]

示例3:去除某个非 _id 字段

集合沿用示例1
我们还可以指定在输出中去掉某个非 _id 字段,这样其它字段都会被输出
const res3 = await db .collection('aggregate_db') .aggregate() .project({ 'scores.chinese': 0, isbn: 0, // 指定去除 isbn 字段 }) .end();
返回结果如下:
[ { "_id": "xxx", "title": "This is title", "author": "Nobody", "introduction": "......", "scores": { "math": 90, "english": 70 } } ]

示例4:加入计算出的新字段

集合沿用示例1
下面的代码,我们使用 project,在输出中加入了一个新的字段 totalScore
const sumRes = await db .collection('aggregate_db') .aggregate() .project({ _id: 0, totalScore: db.command.aggregate.sum([ '$scores.chinese', '$scores.math', '$scores.english', ]), }) .end();
返回结果如下:
[ { "totalScore": 240 } ]

示例5:加入新的数组字段

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "id": 1, "x": 1, "y": 2 }
下面的代码,我们使用 project,把 xy 字段,放入到一个新的数组字段 coordinate 中:
const res = await db .collection('aggregate_db') .aggregate() .project({ coordinate: ['$x', '$y'], }) .end();
返回结果如下:
[ { "_id": "xxx", "coordinate": [1, 2] } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().project('4').end();

错误信息

{ "errCode": 156401, "errMsg": "project 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际project语句 const sumRes = await db .collection('aggregate_db') .aggregate() .project({ _id: 0, name: 1, totalScore: db.command.aggregate.sum([ '$scores.chinese', '$scores.math', '$scores.english', ]), }) .end(); }

replaceRoot

支持端:小程序,小游戏。
聚合阶段。指定一个已有字段作为输出的根节点,也可以指定一个计算出的新字段作为根节点。

参数

object: Object

返回值

Aggregate

API 说明

replaceRoot 使用形式如下:
replaceRoot({ newRoot: <表达式> })
表达式格式如下:
格式
说明
<字段名>
指定一个已有字段作为输出的根节点(如果字段不存在则报错)
<对象>
计算一个新字段,并且把这个新字段作为根节点

示例1:使用已有字段作为根节点

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "name": "SFLS", "score": { "chinese": 22, "english": 21, "math": 18, "other": 123 } }
下面的代码使用 replaceRoot,把 score 字段作为根节点输出:
const res = await db .collection('aggregate_db') .aggregate() .replaceRoot({ newRoot: '$score', }) .end();
返回结果如下:
[ { "chinese": 22, "math": 18, "english": 21, "other": 123 } ]

示例2:使用计算出的新字段作为根节点

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "first_name": "四郎", "id": 1, "last_name": "黄" } { "_id": "xxx", "first_name": "邦德", "id": 2, "last_name": "马" }
下面的代码使用 replaceRoot,把 first_namelast_name 拼在一起:
const res = await db .collection('aggregate_db') .aggregate() .replaceRoot({ newRoot: { full_name: db.command.aggregate.concat(['$last_name', '$first_name']), }, })
返回结果如下:
[{"full_name":"黄四郎"}, {"full_name":"马邦德"}]

错误语法

await db .collection('dbcommand_error_todos') .aggregate() .replaceRoot('4') .end();

错误信息

{ "errCode": 156401, "errMsg": "replaceRoot 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 replaceRoot 语句 const res = await db .collection('aggregate_db') .aggregate() .replaceRoot({ newRoot: '$score', }) .end(); }

sample

支持端:小程序,小游戏。
聚合阶段。随机从文档中选取指定数量的记录。

参数

size: number

返回值

Aggregate

API 说明

sample 的形式如下:
sample({ size: <正整数> })
请注意:size 是正整数,否则会出错。

示例:

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "first_name": "四郎", "id": 1, "last_name": "黄" } { "_id": "xxx", "first_name": "邦德", "id": 2, "last_name": "马" }
如果现在进行抽奖活动,需要选出一名幸运用户。那么 sample 的调用方式如下:
const res = await db .collection('aggregate_db') .aggregate() .sample({ size: 1, }) .end();
返回结果如下:
[ { "_id": "xxx", "id": 2, "first_name": "邦德", "last_name": "马" } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().sample('4').end();

错误信息

{ "errCode": 156401, "errMsg": "sample 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 sample 语句 const res = await db .collection('aggregate_db') .aggregate() .sample({ size: 1, }) .end(); }

skip

支持端:小程序,小游戏。
聚合阶段。指定一个正整数,跳过对应数量的文档,输出剩下的文档。

参数

value: number

返回值

Aggregate

示例:

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "first_name": "四郎", "id": 1, "last_name": "黄" } { "_id": "xxx", "first_name": "邦德", "id": 2, "last_name": "马" }
这段代码会跳过查找到的前 1个文档,并且把剩余的文档输出。
const res = await db.collection('aggregate_db').aggregate().skip(1).end();
返回结果如下:
[ { "_id": "xxx", "id": 2, "first_name": "邦德", "last_name": "马" } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().skip('4').end();

错误信息

{ "errCode": 156401, "errMsg": "skip 值必须是一个整型" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 skip 语句 const res = await db.collection('aggregate_db').aggregate().skip(1).end(); }

sort

支持端:小程序,小游戏。
聚合阶段。根据指定的字段,对输入的文档进行排序。

参数

object: Object

返回值

Aggregate

API 说明

形式如下:
sort({ <字段名1>: <排序规则>, <字段名2>: <排序规则>, })
<排序规则>可以是以下取值:
    1 代表升序排列(从小到大);
    -1 代表降序排列(从大到小);

示例:

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "age": 18, "author": "stark", "id": 1, "score": 80 } { "_id": "xxx", "age": 18, "author": "bob", "id": 2, "score": 60 } { "_id": "xxx", "age": 19, "author": "li", "id": 3, "score": 55 } { "_id": "xxx", "age": 22, "author": "jimmy", "id": 4, "score": 60 } { "_id": "xxx", "age": 33, "author": "justan", "id": 5, "score": 95 }
升序/降序排列
const res = await db .collection('aggregate_db') .aggregate() .sort({ age: -1, score: 1, }) .end();
返回结果如下:
[ { "_id": "xxx", "id": 5, "author": "justan", "score": 95, "age": 33 }, { "_id": "xxx", "id": 4, "author": "jimmy", "score": 60, "age": 22 }, { "_id": "xxx", "id": 3, "author": "li", "score": 55, "age": 19 }, { "_id": "xxx", "id": 2, "author": "bob", "score": 60, "age": 18 }, { "_id": "xxx", "id": 1, "author": "stark", "score": 80, "age": 18 } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().sort('4').end();

错误信息

{ "errCode": 156401, "errMsg": "sort 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 sort 句 const res = await db .collection('aggregate_db') .aggregate() .sort({ age: -1, score: 1, }) .end(); }

sortByCount

支持端:小程序,小游戏。
聚合阶段。根据传入的表达式,将传入的集合进行分组(group)。然后计算不同组的数量,并且将这些组按照它们的数量进行排序,返回排序后的结果。

参数

object: Object

返回值

Aggregate

API 说明

sortByCount 的调用方式如下:
sortByCount(<表达式>)
表达式的形式是:$ + 指定字段。请注意:不要漏写 $ 符号。

示例1: 统计基础类型

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "category": "Web" } { "_id": "xxx", "category": "Web" } { "_id": "xxx", "category": "Life" }
下面的代码就可以统计文章的分类信息,并且计算每个分类的数量。即对 category 字段执行 sortByCount 聚合操作。
const res = await db .collection('aggregate_db') .aggregate() .sortByCount('$category') .end();
返回结果如下:
[ { "_id": "Web", "count": 2 }, { "_id": "Life", "count": 1 } ]

示例2: 解构数组类型

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "name": "demo", "tags": [ "JavaScript", "C#" ] } { "_id": "xxx", "name": "demo", "tags": [ "Go", "C#" ] } { "_id": "xxx", "name": "demo", "tags": [ "Go", "Python", "JavaScript" ] }
如何统计文章的标签信息,并且计算每个标签的数量?因为 tags 字段对应的数组,所以需要借助 unwind 操作解构 tags 字段,然后再调用 sortByCount
const res = await db .collection('aggregate_db') .aggregate() .unwind('$tags') .sortByCount('$tags') .end();
返回结果如下:
[ { "_id": "Go", "count": 2 }, { "_id": "C#", "count": 2 }, { "_id": "JavaScript", "count": 2 }, { "_id": "Python", "count": 1 } ]

错误语法

await db .collection('dbcommand_error_todos') .aggregate() .sortByCount(4) .end();

错误信息

{ "errCode": 156401, "errMsg": "sortByCount 值必须是一个字符串" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 sortByCount 语句 const res = await db .collection('aggregate_db') .aggregate() .unwind('$tags') .sortByCount('$tags') .end(); }

unwind

支持端:小程序,小游戏。
聚合阶段。使用指定的数组字段中的每个元素,对文档进行拆分。拆分后,文档会从一个变为一个或多个,分别对应数组的每个元素。

参数

value: string|object

返回值

Aggregate

API 说明

使用指定的数组字段中的每个元素,对文档进行拆分。拆分后,文档会从一个变为一个或多个,分别对应数组的每个元素。
unwind 有两种使用形式:
    1.参数是一个字段名
unwind(<字段名>)
    2.参数是一个对象
unwind({ path: <字段名>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> })
字段
类型
说明
path
string
想要拆分的数组的字段名,需要以 $ 开头。
includeArrayIndex
string
可选项,传入一个新的字段名,数组索引会保存在这个新的字段上。新的字段名不能以 $ 开头。
preserveNullAndEmptyArrays
boolean
如果为 true,那么在 path 对应的字段为 null、空数组或者这个字段不存在时,依然会输出这个文档;如果为 false,unwind 将不会输出这些文档。默认为 false。

示例1:拆分数组

假设集合 aggregate_db 有如下记录:
{ "_id": "xxx", "id": 1, "product": "tshirt", "size": [ "S", "M", "L" ] } { "_id": "xxx", "id": 2, "product": "pants", "size": [] } { "_id": "xxx", "id": 3, "product": "socks", "size": null } { "_id": "xxx", "id": 4, "product": "trousers", "size": [ "S" ] } { "_id": "xxx", "id": 5, "product": "sweater", "size": [ "M", "L" ] }
我们根据 size 字段对这些文档进行拆分
const res = await db .collection('aggregate_db') .aggregate() .unwind('$size') .end();
返回结果如下:
[ { "_id": "xxx", "id": 1, "product": "tshirt", "size": "S" }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "M" }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "L" }, { "_id": "xxx", "id": 4, "product": "trousers", "size": "S" }, { "_id": "xxx", "id": 5, "product": "sweater", "size": "M" }, { "_id": "xxx", "id": 5, "product": "sweater", "size": "L" } ]

示例2:拆分后,保留原数组的索引

集合沿用示例1
我们根据 size 字段对文档进行拆分后,想要保留原数组索引在新的 index 字段中。
const res = await db .collection('aggregate_db') .aggregate() .unwind({ path: '$size', includeArrayIndex: 'index', }) .end();
返回结果如下:
[ { "_id": "xxx", "id": 1, "product": "tshirt", "size": "S", "index": 0 }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "M", "index": 1 }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "L", "index": 2 }, { "_id": "xxx", "id": 4, "product": "trousers", "size": "S", "index": 0 }, { "_id": "xxx", "id": 5, "product": "sweater", "size": "M", "index": 0 }, { "_id": "xxx", "id": 5, "product": "sweater", "size": "L", "index": 1 } ]

示例3:保留字段为空的文档

集合沿用示例1
如果想要在输出中保留 size 为空数组、null,或者 size 字段不存在的文档,可以使用 preserveNullAndEmptyArrays 参数
const res = await db .collection('aggregate_db') .aggregate() .unwind({ path: '$size', preserveNullAndEmptyArrays: true, }) .end();
返回结果如下:
[ { "_id": "xxx", "id": 1, "author": "stark", "score": 80 }, { "_id": "xxx", "id": 2, "author": "stark", "score": 85 }, { "_id": "xxx", "id": 3, "author": "bob", "score": 60 }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "S" }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "M" }, { "_id": "xxx", "id": 1, "product": "tshirt", "size": "L" }, { "_id": "xxx", "id": 2, "product": "pants" }, { "_id": "xxx", "id": 3, "product": "socks", "size": null }, { "_id": "xxx", "id": 4, "product": "trousers", "size": "S" }, { "_id": "xxx", "id": 5, "product": "sweater", "size": "M" }, { "_id": "xxx", "id": 5, "product": "sweater", "size": "L" } ]

错误语法

await db.collection('dbcommand_error_todos').aggregate().unwind(4).end();

错误信息

{ "errCode": 156401, "errMsg": "unwind 值必须是一个对象" }

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际uuwind语句 const res = await db .collection('aggregate_db') .aggregate() .unwind('$size') .end(); }

end

支持端:小程序,小游戏。
标志聚合操作定义完成,发起实际聚合操作。

返回值

Promise.<Object>
属性
类型
说明
list
Array.<any>
聚合结果列表

示例:

const res = await db .collection('aggregate_db') .aggregate() .unwind({ path: '$size', preserveNullAndEmptyArrays: true, }).end();

兼容说明

// 版本比较 canUseCommand(version1) { const compareVersion = '3.39.0.0'; const v1 = version1.split('.').map(Number); const v2 = compareVersion.split('.').map(Number); for (let i = 0; i < v1.length; i++) { if (v1[i] > v2[i]) { return true; } else if (v1[i] < v2[i]) { return false; } } return true; }; const systemInfo = tt.getSystemInfoSync(); if(canUseCommand(res.SDKUpdateVersion) { // 附实际 end 调用语句 const res = await db .collection('aggregate_db') .aggregate() .unwind({ path: '$size', preserveNullAndEmptyArrays: true, }).end(); }