MongoDB中的嵌套List操作

前言

MongoDB区别Mysql的地方,就是MongoDB支持文档嵌套,比如最近业务中就有一个在音频转写结果中进行对话场景,一个音频中对应多轮对话,这些音频数据和对话信息就存储在MongoDB中文档中。集合结构大致如下

{"_id":23424234234324234,"audioId": 2689944,"contextId": "cht000d24ab@dx187d1168a449a4b540","dialogues": [{"ask": "今天是礼拜天?","answer": "是的","createTime": 1697356990966}, {"ask": "你也要加油哈","answer": "奥利给!","createTime": 1697378011483}, {"ask": "下周见","answer": "拜拜!","createTime": 1697378072063}]
}

下面简单介绍几个业务中用到的简单操作。

查询嵌套List的长度大小

    public Integer getDialoguesSize(Long audioId) {Integer datasSize = 0;List<Document> group = Arrays.asList(new Document("$match",new Document("audioId",new Document("$eq", audioId))), new Document("$match",new Document("dialogues",new Document("$exists", true))), new Document("$project",new Document("datasSize",new Document("$size", "$dialogues"))));AggregateIterable<Document> aggregate = generalCollection.aggregate(group);Document document = aggregate.first();if (document != null) {datasSize = (Integer) document.get("datasSize");}return datasSize;}

根据嵌套List中属性查询

下面的代码主要查询指定audioId中的dialogues集合中小于createTime,并且根据limit分页查询,这里用到了MongoDB中的Aggregates和unwind来进行聚合查询,具体使用细节,可以参见MongoDB官方文档

    public AIDialoguesResultDTO queryAiResult(Long audioId, Long createTime, Integer limit) {AIDialoguesResultDTO aiDialoguesResultDTO = new AIDialoguesResultDTO();List<Bson> pipeline = Arrays.asList(Aggregates.match(Filters.eq("audioId", audioId)),Aggregates.unwind("$dialogues"),Aggregates.match(Filters.lt("dialogues.createTime", createTime)),Aggregates.sort(Sorts.descending("dialogues.createTime")),Aggregates.limit(limit));AggregateIterable<Document> aggregate = generalCollection.aggregate(pipeline);List<AIDialoguesResult> aiDialoguesResultList = new ArrayList<>();String contextId = Constant.EMPTY_STR;for (Document document : aggregate) {AIDialoguesResult aiDialoguesResult = new AIDialoguesResult();List<String> key = Collections.singletonList("dialogues");aiDialoguesResult.setAnswer(document.getEmbedded(key, Document.class).getString("answer"));aiDialoguesResult.setAsk(document.getEmbedded(key, Document.class).getString("ask"));aiDialoguesResult.setCreateTime(document.getEmbedded(key, Document.class).getLong("createTime"));aiDialoguesResultList.add(aiDialoguesResult);contextId = document.getString("contextId");}if (!CollectionUtils.isEmpty(aiDialoguesResultList)) {aiDialoguesResultList = aiDialoguesResultList.stream().sorted(Comparator.comparingLong(AIDialoguesResult::getCreateTime)).collect(Collectors.toList());}aiDialoguesResultDTO.setCount(aiDialoguesResultList.size());aiDialoguesResultDTO.setContextId(contextId);aiDialoguesResultDTO.setResult(aiDialoguesResultList);return aiDialoguesResultDTO;}

当然,我们还有一种比较简单的写法

    public AIDialoguesResultDTO queryAiResultBackupVersion(Long audioId, Long createTime, Integer limit) {Bson query = and(eq("audioId", audioId));AITextResult aiTextResult = mongoDao.findSingle(query, AITextResult.class);AIDialoguesResultDTO aiDialoguesResultDTO = new AIDialoguesResultDTO();if (Objects.isNull(aiTextResult)) {aiDialoguesResultDTO.setResult(Collections.emptyList());aiDialoguesResultDTO.setCount(0);aiDialoguesResultDTO.setContextId("");}List<AIDialoguesResult> aiDialoguesResultList = aiTextResult.getDialogues();if (CollectionUtils.isEmpty(aiDialoguesResultList)) {return aiDialoguesResultDTO;}Long finalCreateTime = createTime;List<AIDialoguesResult> afterFilterAiDialoguesResultList =aiDialoguesResultList.stream().filter(t -> t.getCreateTime()< finalCreateTime).sorted(Comparator.comparingLong(AIDialoguesResult::getCreateTime).reversed()).limit(limit).collect(Collectors.toList());if (CollectionUtils.isEmpty(afterFilterAiDialoguesResultList)) {aiDialoguesResultDTO.setCount(0);} else {aiDialoguesResultDTO.setCount(afterFilterAiDialoguesResultList.size());}afterFilterAiDialoguesResultList = afterFilterAiDialoguesResultList.stream().sorted(Comparator.comparingLong(AIDialoguesResult::getCreateTime)).collect(Collectors.toList());aiDialoguesResultDTO.setResult(afterFilterAiDialoguesResultList);aiDialoguesResultDTO.setContextId(aiTextResult.getContextId());return aiDialoguesResultDTO;}

上面这种写法比较直接,就是直接audioId进行匹配查询, 然后将当前文档中的dialogues全部加载到内存中,然后在内存中进行排序,分页返回,显然如果dialogues集合长度很大,对内存占用会比较高。

嵌套List的增量追加

对于dialogues数组,如果我们要向dialogues追加元素,我们可以把audioId对应的dialogues全部取出来,然后在List后面追加一个元素,大致代码如下

    public void saveAiResult(SaveAIResultDTO saveAIResultDTO) {Long audioId = saveAIResultDTO.getAudioId();Bson filter = Filters.eq("audioId", audioId);AITextResult aiTextResult = mongoDao.findSingle(filter, AITextResult.class);if (Objects.isNull(aiTextResult)) {aiTextResult = AITextResult.buildAiTextResult(saveAIResultDTO);mongoDao.saveOrUpdate(aiTextResult);return;}List<AIDialoguesResult> aiDialoguesResults = aiTextResult.getDialogues();AIDialoguesResult aiDialoguesResult = new AIDialoguesResult();aiDialoguesResult.setCreateTime(new Date().getTime());aiDialoguesResult.setAsk(saveAIResultDTO.getAsk());aiDialoguesResult.setAnswer(saveAIResultDTO.getAnswer());aiDialoguesResults.add(aiDialoguesResult);aiTextResult.setDialogues(aiDialoguesResults);mongoDao.saveOrUpdate(aiTextResult);}

上面这种写法本身没有什么问题,但是如果dialogues集合大小比较大,每次追加都将dialogues全部取出来进行追加操作,可能比较占用内存,我们可以利用MongoDB中的push操作,直接追加

    public void saveAiResultIncremental(SaveAIResultDTO saveAIResultDTO) {Long audioId = saveAIResultDTO.getAudioId();Document query = new Document("audioId", audioId);Bson projection = Projections.fields(Projections.include("contextId"), Projections.excludeId());FindIterable<Document> result = generalCollection.find(query).projection(projection);AITextResult aiTextResult;if (!result.iterator().hasNext()) {aiTextResult = AITextResult.buildAiTextResult(saveAIResultDTO);mongoDao.saveOrUpdate(aiTextResult);return;}AIDialoguesResult aiDialoguesResult = new AIDialoguesResult();aiDialoguesResult.setCreateTime(new Date().getTime());aiDialoguesResult.setAsk(saveAIResultDTO.getAsk());aiDialoguesResult.setAnswer(saveAIResultDTO.getAnswer());Bson update = push("dialogues", aiDialoguesResult);Bson filter = Filters.eq("audioId", audioId);generalCollection.updateOne(filter, update);}

总结

既然选择了MongoDB,就不能继续沿用Mysql的查询风格,要学会利用MongoDB的特性,否则往往达不到预期效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/106882.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探寻JWT的本质:它是什么?它有什么作用?

JWT&#xff08;JSON Web Token&#xff09;是一种基于 JSON 格式的轻量级令牌&#xff08;token&#xff09;协议&#xff0c;它被广泛应用于网络应用程序的身份验证和授权。相较于传统的 session-based 认证机制&#xff0c;JWT 具有更好的扩展性和互操作性&#xff0c;同时也…

在C++中++a和a++有什么区别?

2023年10月16日&#xff0c;周一中午 a和a在语义上的区别 a是先进行运算(增加1),然后返回新值。 a是先返回原值,然后进行运算(增加1)。 a和a在效率上的区别 a直接返回新值,不需要临时变量保存原值。 而a需要先返回原值,然后再进行增加1的操作。这需要使用一个临时变量来保存…

LeetCode LCR 191. 按规则计算统计结果【前后缀分解】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

压力山大题

找不到工作的面试者总结 提示&#xff1a;写文章的时候&#xff0c;我还在找工作&#xff01;&#xff01;&#xff01; 文章目录 找不到工作的面试者总结前言一、JAVA面死题1. OOP是什么2. 重载与重写的区别3. java基本类型4. String、StringBuffer、StringBuilder的区别5. 接…

word写论文遇到数字和文字中间空格删不掉

一、如何删除&#xff1f; 1、选中需要有数字和汉字那段文字 2、点击段落下拉 3、找到中文版式 4、将【自动调整中文与数字的间距】取消勾选&#xff08;不要勾选&#xff09; 5、点击确定即可删除啦

Maven 使用教程

一、什么是Maven&#xff1f; 乍一看&#xff0c;Maven可能是许多东西&#xff0c;但简而言之&#xff0c;Maven.试图将模式应用于项目的构建基础架构&#xff0c;以便通过提供使用最佳实践的明确途径来提高理解力和生产力。Maven本质上是一个项目管理和理解工具&#xff0c;因…

SQL之alter的用法简介

SQL之alter的用法简介 ALTER TABLE是SQL中的一个命令&#xff0c;它用于修改已经存在的表的结构&#xff0c;而不改变其原始数据。以下是一些ALTER TABLE的用法&#xff1a; 1&#xff09;增加列&#xff08;Add Column&#xff09;&#xff1a; ALTER TABLE table_name ADD…

强化科技创新“辐射力”,中国移动的数智化大棋局

作者 | 曾响铃 文 | 响铃说 丝滑流畅的5G连接、每时每刻的数字生活服务、无处不在的智能终端、拟人交流的AI助手、梦幻般的XR虚拟现实、直接感受的裸眼3D…… 不知不觉&#xff0c;那个科幻片中的世界&#xff0c;越来越近。 数智化新世界的“气氛”&#xff0c;由一个个具…

flinkdashboard未授权

flinkwebui 增加账号密码 yum install httpd-tools -y htpasswd -c /usr/local/nginx/conf.d/.ngpasspd flink2024 flink_2024 再输入密码 修改flink.conf 我们可以通过./conf/flink-conf.yaml来设置web服务器的ip和端口: rest.address rest.port:8084 安装nginx ./config…

VR太空舱体验馆VR神舟返回舱VR虚拟现实科技科普乐园

VR航天航空设备&#xff0c;寓教于乐 VR科技正成为航天航空领域的新宠。作为一种沉浸式的数字技术&#xff0c;VR(Virtual Reality&#xff0c;虚拟现实)能够为用户创造出逼真的虚拟环境&#xff0c;让人们仿佛身临其境。借助VR技术&#xff0c;我们可以带领学生和游客深入了解…

scrapy针对302请求的处理与重试配置

不修改任何配置&#xff0c;scrapy针对302请求时如何处理的&#xff1f; 默认情况下&#xff0c;当爬虫发送请求并收到 HTTP 302 重定向响应时&#xff0c;Scrapy 会自动跟随重定向&#xff0c;也就是说&#xff0c;它会自动向重定向的 URL 发送一个新的请求&#xff0c;并且在…

矩阵键盘反转扫描

/*----------------------------------------------- 内容&#xff1a;如计算器输入数据形式相同 从右至左 ------------------------------------------------*/ #include<reg52.h> //包含头文件&#xff0c;一般情况不需要改动&#xff0c;头文件包含特殊功能寄存器的定…

LangChain结合milvus向量数据库以及GPT3.5结合做知识库问答之一 --->milvus的docker compose安装

https://github.com/milvus-io/milvus/releaseshttps://github.com/milvus-io/milvus/releases 以下步骤均在Linux环境中进行&#xff1a; 将milvus-standalone-docker-compose.yml下载到本地。 1、新建一个目录milvus 2、将milvus-standalone-docker-compose.yml放到milvu…

Spring Cloud--Nacos+@RefreshScope实现配置的动态更新

原文网址&#xff1a;Spring Cloud--NacosRefreshScope实现配置的动态更新_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍SpringCloud整合Nacos使用RefreshScope实现动态更新配置。 官网 Nacos Spring Cloud 快速开始 动态更新的介绍 动态更新的含义&#xff1a;修改应…

区块链(11):java区块链项目之页面部分实现

addPeer.html <!DOCTYPE html> <html> <head><meta charset="utf-8"> <title>java区块链</title><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="styles…

iOS-2023面试最新-逆向题-视觉

1、逆向思路 界面分析。Cycript、Reveal 代码分析。MachOView、class-dump、Hopper Disassembler、ida 动态调试。debugserver、LLDB 代码编写。代码注入&#xff0c;重签名&#xff0c;打包 2、ios签名机制 3、Mach-O&#xff0c;ASLR 4、LLVM 5、OpenSSH登录iPhone&a…

2023_Spark_实验十八:安装FinalShell

下载安装包 链接&#xff1a;https://pan.baidu.com/s/14cOJDcezzuwUYowPsOA-sg?pwd6htc 提取码&#xff1a;6htc 下载文件名称&#xff1a;FinalShell.zip 二、安装 三、启动FinalShell 四、连接远程 linux 服务器 先确保linux系统已经开启&#xff0c;不然连接不上 左边…

关于雅思听力答案限定字数的解释。

1. No more than three words and/or a number&#xff1a;31&#xff0c;可以填3/2/1个单词&#xff1b;1个数字&#xff1b;3/2/1个单词1个数字 2. No more than three words and/or numbers&#xff1a;3n&#xff0c;可以填3/2/1个单词&#xff1b;n个数字&#xff1b;3/2…

一款优秀的文件外发控制软件 具备哪些优势?

随着越来越多的公司在网上开展业务&#xff0c;网络安全漏洞也相应增加。因此&#xff0c;企业需要保护自己的数据&#xff0c;防止数据泄露&#xff0c;给企业带来损失。近几年来&#xff0c;企业数据泄露事件频发&#xff0c;给许多企业都带来巨大创伤。 乌克兰电力公司在201…

3.Vue-在Vue框架中搭建路由

题记 以下是在vue框架中搭建路由的全过程&#xff0c;包括全部代码。 创建路由 如果你的文件中没有 router文件夹&#xff0c;可以使用以下命令创建&#xff1a; vue add router 注意&#xff1a;生成的路由文件会因为选择的自定义选项不同&#xff0c;而有所差异 生成的代码…