MongoDB聚合运算符:$firstN

文章目录

$firstN聚合运算符返回分组中前n个元素的聚合,只有在分组元素是有序的情况下才有意义,如果分组中的元素个数小于n,将返回分组中所有的元素。

语法

js 复制代码
{
   $firstN:
      {
         input: <expression>,
         n: <expression>
      }
}
  • input指定要从文档中获取的字段,可以是任何表达式
  • nn 必须是正整数表达式,可以是常量,也可以是$group_id 值。

使用

空值或缺失值的处理

  • $firstN不会过滤掉空值
  • 缺失的值会被$firstN转换为null

下面的聚合返回每个分组的前5个文档:

js 复制代码
db.aggregate( [
   {
      $documents: [
         { playerId: "PlayerA", gameId: "G1", score: 1 },
         { playerId: "PlayerB", gameId: "G1", score: 2 },
         { playerId: "PlayerC", gameId: "G1", score: 3 },
         { playerId: "PlayerD", gameId: "G1"},
         { playerId: "PlayerE", gameId: "G1", score: null }
      ]
   },
   {
      $group:
      {
         _id: "$gameId",
         firstFiveScores:
            {
               $firstN:
                  {
                     input: "$score",
                     n: 5
                  }
            }
      }
   }
] )

在这个示例中:

  • documents创建了一些包含运动员得分的字面量文档
  • $group对文档按照gameId对文档进行分组,本例中只有一个gameIdG1
  • PlayerD的得分得分不存在,PlayerE的得分为null,这两者的值都为都会被认为是null
  • input: "$score"指定给firstFiveScores字段并返回一个数组
  • 由于没有排序标准,因此返回前 5 个分数字段
js 复制代码
[
   {
      _id: 'G1',
      firstFiveScores: [ 1, 2, 3, null, null ]
   }
]

f i r s t N 与 firstN与 firstN与topN对比

$firstN$topN运算符返回的结果类似,但是:

  • 如果文档来自于$group且已经排序,应该使用$firstN
  • 如果要排序并且返回前n个元素,使用$topN一个运算就可以搞定
  • $firstN可以用于聚合表达式,但是$topN不可以

关于窗口功能和聚合表达式的支持

  • $firstN支持作为聚合表达式
  • $firstN同时支持作为窗口操作符

内存限制

调用$firstN的聚合管道受100MB的限制,如果单个组超出此限制,聚合将失败并返回错误。

举例

使用下面的脚本创建gamescores集合:

js 复制代码
db.gamescores.insertMany([
   { playerId: "PlayerA", gameId: "G1", score: 31 },
   { playerId: "PlayerB", gameId: "G1", score: 33 },
   { playerId: "PlayerC", gameId: "G1", score: 99 },
   { playerId: "PlayerD", gameId: "G1", score: 1 },
   { playerId: "PlayerA", gameId: "G2", score: 10 },
   { playerId: "PlayerB", gameId: "G2", score: 14 },
   { playerId: "PlayerC", gameId: "G2", score: 66 },
   { playerId: "PlayerD", gameId: "G2", score: 80 }
])

查找单场比赛的前三名运动员得分

使用$firstN单场比赛的前三名得分:

js 复制代码
db.gamescores.aggregate( [
   {
      $match : { gameId : "G1" }
   },
   {
      $group:
         {
            _id: "$gameId",
            firstThreeScores:
               {
                  $firstN:
                  {
                     input: ["$playerId", "$score"],
                     n:3
                  }
               }
         }
   }
] )

在本例中:

  • 使用match过滤出gameIdG1的文档
  • 使用$group按照gameId进行分组
  • 使用input : ["$playerId"," $score"].$firstN指定输入字段
  • 使用$fristN指定n:3返回G1游戏前三个文档

操作返回的结果如下:

js 复制代码
[
   {
      _id: 'G1',
      firstThreeScores: [ [ 'PlayerA', 31 ], [ 'PlayerB', 33 ], [ 'PlayerC', 99 ] ]
   }
]

查找多场比赛中前三名运动员的得分

使用$firstN查找每个比赛中前n个输入字段:

js 复制代码
db.gamescores.aggregate( [
   {
      $group:
      {
      _id: "$gameId", playerId:
         {
            $firstN:
               {
                  input: [ "$playerId","$score" ],
                  n: 3
               }
         }
      }
   }
] )

在本例聚合管道中:

  • 使用$group根据gameId进行分组
  • 使用$firstNn:3返回比赛前三个文档
  • firstN指定输入字段input : ["$playerId", "$score"]

操作返回下面的结果:

js 复制代码
[
   {
      _id: 'G1',
      playerId: [ [ 'PlayerA', 31 ], [ 'PlayerB', 33 ], [ 'PlayerC', 99 ] ]
   },
   {
      _id: 'G2',
      playerId: [ [ 'PlayerA', 10 ], [ 'PlayerB', 14 ], [ 'PlayerC', 66 ] ]
   }
]

s o r t 与 sort与 sort与firstN一起使用

在管道中较早使用$sort阶段可能会影响$firstN

js 复制代码
db.gamescores.aggregate( [
      { $sort : { score : -1 } },
      {

         $group:
         { _id: "$gameId", playerId:
            {
               $firstN:
                  {
                     input: [ "$playerId","$score" ],
                     n: 3
                  }
            }
         }
      }
   ] )

在这个例子中:

  • {$sort : { score : -1 } }将得分最高的排在分组最后
  • firstN返回分组中前三个得分最高的
js 复制代码
db.gamescores.aggregate( [
      { $sort : { score : -1 } },
      {

         $group:
         { _id: "$gameId", playerId:
            {
               $firstN:
                  {
                     input: [ "$playerId","$score" ],
                     n: 3
                  }
            }
         }
      }
   ] )

操作返回下面的结果:

js 复制代码
[
   {
      _id: 'G2',
      playerId: [ [ 'PlayerD', 80 ], [ 'PlayerC', 66 ], [ 'PlayerB', 14 ] ]
   },
   {
      _id: 'G1',
      playerId: [ [ 'PlayerC', 99 ], [ 'PlayerB', 33 ], [ 'PlayerA', 31 ] ]
   }
]

根据group的键计算n

可以动态的指定n的值,在下面的例子中$cond表达式被用于gameId字段

js 复制代码
db.gamescores.aggregate([
   {
      $group:
      {
         _id: {"gameId": "$gameId"},
         gamescores:
            {
               $firstN:
                  {
                     input: "$score",
                     n: { $cond: { if: {$eq: ["$gameId","G2"] }, then: 1, else: 3 } }
                  }
            }
      }
   }
] )

在本例的管道中:

  • 使用$group根据gameId进行分组
  • 使用input : "$score"指定$firstN输入字段
  • 如果gameIdG2n为1,否则n为3

操作返回下面的结果:

js 复制代码
[
   { _id: { gameId: 'G1' }, gamescores: [ 31, 33, 99 ] },
   { _id: { gameId: 'G2' }, gamescores: [ 10 ] }
]

在聚合表达式中使用$firstN

请看下面的聚合:

js 复制代码
db.aggregate( [
   {
      $documents: [
         { array: [10, 20, 30, 40] } ]
   },
   { $project: {
      firstThreeElements:{
                           $firstN:
                           {
                              input: "$array",
                              n: 3
                           }
                        }
               }
   }
] )
  • $documents创建了一个包含一个数组的字面量文档
  • $project用于返回$firstN的输出
  • _id被输出省略_id:0
  • $firstN使用输入数组[10, 20, 30, 40]
  • 返回输入文档数组的前三个元素

操作返回下面的结果:

js 复制代码
[
   { firstThreeElements: [ 10, 20, 30 ] }
]
相关推荐
沉到海底去吧Go2 分钟前
【图片自动识别改名】识别图片中的文字并批量改名的工具,根据文字对图片批量改名,基于QT和腾讯OCR识别的实现方案
数据库·qt·ocr·图片识别自动改名·图片区域识别改名·pdf识别改名
老纪的技术唠嗑局19 分钟前
重剑无锋,大巧不工 —— OceanBase 中的 Nest Loop Join 使用技巧分享
数据库·sql
未来之窗软件服务1 小时前
JAVASCRIPT 前端数据库-V6--仙盟数据库架构-—-—仙盟创梦IDE
数据库·数据库架构·仙盟创梦ide·东方仙盟·东方仙盟数据库
一只爱撸猫的程序猿2 小时前
构建一个简单的智能文档问答系统实例
数据库·spring boot·aigc
nanzhuhe2 小时前
sql中group by使用场景
数据库·sql·数据挖掘
消失在人海中2 小时前
oracle sql 语句 优化方法
数据库·sql·oracle
Clang's Blog3 小时前
一键搭建 WordPress + MySQL + phpMyAdmin 环境(支持 PHP 版本选择 & 自定义配置)
数据库·mysql·php·wordpr
zzc9213 小时前
MATLAB仿真生成无线通信网络拓扑推理数据集
开发语言·网络·数据库·人工智能·python·深度学习·matlab
未来之窗软件服务3 小时前
JAVASCRIPT 前端数据库-V1--仙盟数据库架构-—-—仙盟创梦IDE
数据库·数据库架构·仙盟创梦ide·东方仙盟数据库
LjQ20403 小时前
网络爬虫一课一得
开发语言·数据库·python·网络爬虫