MongoDB - 多次获取第一个匹配的文档 - 哪个更好?

如何解决MongoDB - 多次获取第一个匹配的文档 - 哪个更好?

想象一个集合是这样的:

{
  created_at: Date,color: string,// 'blue' | 'red' | 'yellow'
}

我在一个集合中有数千或数百万个文档,其中包含随机 created_at 日期时间和不同颜色。 现在我想拥有最新创建的颜色“蓝色”的文档和最新创建的颜色“红色”的文档。

哪种方法最好? (随意推荐另一个)

A) 多个并行查询

const latest = await Promise.all([
   collection.findOne({ color: 'blue' },{ sort: { created_at: -1 } }),collection.findOne({ color: 'red' },]);

B) 一个聚合查询 - 组

const latest = await collection.aggregate([
  { $match: { color: { $in: ['blue','red'] } } },{ $sort: { created_at: -1 } },{
    $group: {
      _id: "$color",latest: { $first: "$$ROOT" }
    }
  },]).toArray();

C) 一个聚合查询 - 方面

const latest = await collection.aggregate([
  { $match: { color: { $in: ['blue',{
    $facet: {
      blue: [
        { $match: { color: 'blue' } },{ $limit: 1 },],red: [
        { $match: { color: 'red' } },}
  },]).toArray();

哪个性能最好?如果我想为超过 2 种颜色执行此操作怎么办?

附带问题:实际上,对于 $facet 操作,我很想知道这个问题。由于 $facet 不能使用索引,因此在某些情况下并行执行多个查询似乎更好。如果每组有很多文档(在本例中为“颜色”),使用索引似乎很有用。所以我想选项C不是很好。对于选项 B,我想知道 MongoDB 是否首先需要获取所有符合通用条件的文档,对所有文档进行排序,将所有文档分组,然后只取第一个...

提前致谢!

解决方法

您的解决方案都没有使用索引(我猜是因为您还没有创建它)。

创建以下索引:

{ color: 1,created_at: -1 }

然后您可以对查询运行解释计划并查看它们的行为。

我“认为”第一个会是最快的。

,

似乎选项 A 是最好的,至少在我测试的情况下是这样。

我做了如下性能测试:

我创建了一个包含 3.000.000 个文档和 2 个字段的集合:

  • created_at:2018-01-01T00:00:00.000Z 和 2030-01-01T00:00:00.000Z 之间的随机日期
  • color:随机字符串,31 个不同的选项

我做了一个查询,为 17 种不同颜色的每一种获取最新创建的文档。

结果

没有索引 { color: 1,created_at: -1 } { created_at: -1,color: 1 }
A1) 一个 FindOne (shell) 70 毫秒 60 毫秒 60 毫秒
A2) FindOnes 并行 (JS) 21944 毫秒 543 毫秒 572 毫秒
B) 聚合 - 组 - 首先 QueryExceededMemoryLimitNoDiskUseAllowed 9120 毫秒 10200 毫秒
C) 聚合 - 方面 QueryExceededMemoryLimitNoDiskUseAllowed 3860 毫秒 4770 毫秒

选项 A1 是最快的,但这仅适用于一种颜色(我无法通过外壳并行执行)。所以真正的赢家是选项A2!另请注意,A2 是通过连接到外部数据库的本地运行 JS 脚本完成的。它仍然比直接通过 shell 完成的其他选项要快得多。

我检查了并行执行 5 个 findOnes 而不是 17 个的影响:

A3) FindOnes 并行 (JS) | 6656 毫秒 | 334 毫秒 | 339 毫秒

这明显更快。我怀疑如果您需要超过 17 个案例,其他选择可能会更好。它与我的需求无关,所以我没有对此进行测试。


为了完整性,确切的查询:

A1)

db.getCollection('colors').findOne({ color: 'Ivory' },{ sort: { created_at: -1 } })

A2)

const latest = await Promise.all(colors.map((c) => mongodb.collection('colors').findOne({ color: c },{ sort: { created_at: -1 } })));

B)

db.getCollection('colors').aggregate([
  { $match: { color: { $in: [
    'Ivory','Teal','Silver','Purple','Navy blue','Pea green','Gray','Orange','Maroon','Charcoal','Aquamarine','Coral','Fuchsia','Wheat','Lime','Crimson','Khaki'
  ] } } },{ $sort: { created_at: -1 } },{
    $group: {
      _id: "$color",latest: { $first: "$$ROOT" }
    }
  },]);

C)

db.getCollection('colors').aggregate([
  { $match: { color: { $in: [
    'Ivory',{
    $facet: {
      Ivory: [
        { $match: { color: 'Ivory' } },{ $limit: 1 },],Teal: [
        { $match: { color: 'Teal' } },Silver: [
        { $match: { color: 'Silver' } },Purple: [
        { $match: { color: 'Purple' } },Navyblue: [
        { $match: { color: 'Navy blue' } },Peagreen: [
        { $match: { color: 'Pea green' } },Gray: [
        { $match: { color: 'Gray' } },Orange: [
        { $match: { color: 'Orange' } },Maroon: [
        { $match: { color: 'Maroon' } },Charcoal: [
        { $match: { color: 'Charcoal' } },Aquamarine: [
        { $match: { color: 'Aquamarine' } },Coral: [
        { $match: { color: 'Coral' } },Fuchsia: [
        { $match: { color: 'Fuchsia' } },Wheat: [
        { $match: { color: 'Wheat' } },Lime: [
        { $match: { color: 'Lime' } },Crimson: [
        { $match: { color: 'Crimson' } },Khaki: [
        { $match: { color: 'Khaki' } },}
  },]);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res