Mongoose aggregate从数组随机取元素仅返回Users值及过滤方法
问题解决方案
1、仅返回Users字段值的实现方法
你当前的聚合管道执行后返回的是匹配文档的全量字段,要只拿到Users的值,有两种实现方式:
- 方式一(推荐,性能更好):在聚合管道末尾新增
$project投影阶段,指定只返回需要的字段,过滤掉其他无用字段。
调整后的完整代码如下:const winnerRes = await gSchema.aggregate( [ { "$unwind": "$Users" }, { "$sample": { "size": 1 } }, // 新增投影配置 { "$project": { _id: 0, // 0表示不返回默认自带的_id字段 Users: 1 // 1表示返回该字段 }} ] ) // aggregate返回结果始终是数组,取第一条的Users属性即可 const winner = winnerRes[0]?.Users console.log(winner) // 直接输出1234567889 - 方式二:拿到原有聚合结果后,在代码层直接取对应属性,不需要修改聚合管道:
这种方式会查询返回全量文档字段,数据传输和查询开销更大,不推荐在文档字段较多的场景使用。const winnerList = await gSchema.aggregate( [ { "$unwind": "$Users" }, { "$sample": { "size": 1 } } ] ) const winner = winnerList[0]?.Users
2、聚合管道添加过滤条件的方法
Mongoose的aggregate完全支持过滤条件,使用$match管道阶段即可实现。
注意:$match阶段尽量放在聚合管道的最靠前位置,在$unwind、$sample等操作之前先过滤掉不符合要求的文档,能大幅减少后续阶段需要处理的数据量,提升聚合性能,还能避免无效数据进入后续处理流程导致空结果等异常。
举个实际使用示例,比如过滤出Guild为指定值、创建时间在2022-07-01之后、Users数组非空的文档再做后续随机抽取:
const winnerRes = await gSchema.aggregate( [ // 过滤条件放在最前面 { "$match": { Guild: '1234567889', Date: { $gte: new Date('2022-07-01') }, Users: { $exists: true, $ne: [] } }}, { "$unwind": "$Users" }, { "$sample": { "size": 1 } }, { "$project": { _id: 0, Users: 1 }} ] )
$match的语法和普通查询find的查询条件语法完全一致,支持精确匹配、范围匹配、数组匹配、逻辑运算等所有常用查询操作。
内容的提问来源于stack exchange,提问作者Christy
相关产品推荐
相关产品推荐

