当前位置: 首页 > news >正文

MongoDB教程-7

正如在MongoDB关系的最后一章中所看到的,为了在MongoDB中实现规范化的数据库结构,我们使用了引用关系的概念,也被称为手动引用,在这个概念中,我们手动将被引用文档的id存储在其他文档中。然而,在一个文档包含来自不同集合的引用的情况下,我们可以使用MongoDB DBRefs。

DBRefs与手工引用
作为一个例子,我们将使用DBRefs而不是手动引用,考虑一个数据库,我们在不同的集合(address_home、address_office、address_mailing等)中存储不同类型的地址(家庭、办公室、邮件等)。现在,当一个用户集合的文档引用一个地址时,它也需要根据地址类型来指定查找哪个集合。在这种情况下,如果一个文档引用了许多集合的文档,我们应该使用DBRefs。

使用DBRefs
在 DBRefs 中有三个字段 --

$ref - 这个字段指定了被引用文档的集合

$id - 这个字段指定了被引用文档的_id字段

$db - 这是一个可选的字段,包含被引用文档所在的数据库的名称。

考虑一个具有DBRef字段地址的用户文档样本,如代码片段所示

{"_id":ObjectId("53402597d852426020000002"),"address": {"$ref": "address_home","$id": ObjectId("534009e4d852427820000002"),"$db": "tutorialspoint"},"contact": "987654321","dob": "01-01-1991","name": "Tom Benzamin"
}

这里的地址DBRef字段指定引用的地址文件位于tutorialspoint数据库下的address_home集合中,其id为534009e4d852427820000002。

下面的代码动态地在$ref参数指定的集合(在我们的例子中是address_home)中寻找一个id为DBRef中$id参数指定的文档。

>var user = db.users.findOne({"name":"Tom Benzamin"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})

上述代码返回存在于address_home集合中的以下地址文件 -

{"_id" : ObjectId("534009e4d852427820000002"),"building" : "22 A, Indiana Apt","pincode" : 123456,"city" : "Los Angeles","state" : "California"
}

什么是覆盖式查询?
根据MongoDB的官方文档,覆盖式查询是一个查询,其中

查询中的所有字段都是一个索引的一部分。
在查询中返回的所有字段都在同一个索引中。
由于查询中的所有字段都是索引的一部分,MongoDB会匹配查询条件,并使用相同的索引返回结果,而无需实际查看文档内部。由于索引存在于RAM中,从索引中获取数据要比通过扫描文档获取数据快得多。

使用覆盖式查询
为了测试覆盖式查询,请考虑用户集合中的以下文档

{"_id": ObjectId("53402597d852426020000003"),"contact": "987654321","dob": "01-01-1991","gender": "M","name": "Tom Benzamin","user_name": "tombenzamin"
}

我们将首先使用下面的查询为用户集合的性别和用户名称字段创建一个复合索引------。

>db.users.createIndex({gender:1,user_name:1})
{"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1
}

现在,这个索引将涵盖以下查询 --

>db.users.find({gender:"M"},{user_name:1,_id:0})
{ "user_name" : "tombenzamin" }

这就是说,对于上述查询,MongoDB不会去寻找数据库文件。相反,它将从索引数据中获取所需的数据,这是非常快的。

由于我们的索引不包括_id字段,我们已经明确地将它从我们的查询结果集中排除,因为MongoDB默认在每个查询中返回_id字段。所以下面的查询不会被包含在上面创建的索引中------。

>db.users.find({gender:"M"},{user_name:1})
{ "_id" : ObjectId("53402597d852426020000003"), "user_name" : "tombenzamin" }

最后,请记住,一个索引不能覆盖一个查询,如果---。

任何被索引的字段是一个数组
任何一个被索引的字段是一个子文件

分析查询是衡量数据库和索引设计是否有效的一个非常重要的方面。我们将学习经常使用的$explain和$hint查询。

使用$explain
$explain操作符提供了关于查询、查询中使用的索引和其他统计数据的信息。在分析你的索引的优化程度时,它非常有用。

在上一章中,我们已经为用户集合中的字段gender和user_name创建了一个索引,使用的查询方式如下

>db.users.createIndex({gender:1,user_name:1})
{"numIndexesBefore" : 2,"numIndexesAfter" : 2,"note" : "all indexes already exist","ok" : 1
}

我们现在将在以下查询中使用$explain --

>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()

上述 explain() 查询返回以下分析结果 -

{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "mydb.users","indexFilterSet" : false,"parsedQuery" : {"gender" : {"$eq" : "M"}},"queryHash" : "B4037D3C","planCacheKey" : "DEAAE17C","winningPlan" : {"stage" : "PROJECTION_COVERED","transformBy" : {"user_name" : 1,"_id" : 0},"inputStage" : {"stage" : "IXSCAN","keyPattern" : {"gender" : 1,"user_name" : 1},"indexName" : "gender_1_user_name_1","isMultiKey" : false,"multiKeyPaths" : {"gender" : [ ],"user_name" : [ ]},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"gender" : ["[\"M\", \"M\"]"],"user_name" : ["[MinKey, MaxKey]"]}}},"rejectedPlans" : [ ]},"serverInfo" : {"host" : "Krishna","port" : 27017,"version" : "4.2.1","gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e"},"ok" : 1
}

我们现在来看看这个结果集中的字段 -

indexOnly的真值表示这个查询使用了索引。

cursor字段指定了使用的游标类型。BTreeCursor类型表示使用了一个索引,并且给出了所使用的索引的名称。BasicCursor表示在没有使用任何索引的情况下进行了一次全扫描。

n表示返回的匹配文档的数量。

nscannedObjects表示扫描的文件总数。

nscanned表示扫描的文档或索引条目的总数。

使用$hint


$hint操作符强制查询优化器使用指定的索引来运行查询。当你想用不同的索引来测试一个查询的性能时,这特别有用。

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
{ "user_name" : "tombenzamin" }

为了分析上述查询,使用$explain -

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()

由此得出以下结果−

{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "mydb.users","indexFilterSet" : false,"parsedQuery" : {"gender" : {"$eq" : "M"}},"queryHash" : "B4037D3C","planCacheKey" : "DEAAE17C","winningPlan" : {"stage" : "PROJECTION_COVERED","transformBy" : {"user_name" : 1,"_id" : 0},"inputStage" : {"stage" : "IXSCAN","keyPattern" : {"gender" : 1,"user_name" : 1},"indexName" : "gender_1_user_name_1","isMultiKey" : false,"multiKeyPaths" : {"gender" : [ ],"user_name" : [ ]},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"gender" : ["[\"M\", \"M\"]"],"user_name" : ["[MinKey, MaxKey]"]}}},"rejectedPlans" : [ ]},"serverInfo" : {"host" : "Krishna","port" : 27017,"version" : "4.2.1",109"gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e"},"ok" : 1
}

原子操作的模型数据
推荐的维护原子性的方法是将所有相关的信息,经常更新的信息,使用嵌入式文件保存在一个文件中。这将确保单个文档的所有更新都是原子性的。

假设我们创建了一个名为productDetails的集合,并在其中插入了一个文档,如下所示

>db.createCollection("products")
{ "ok" : 1 }
> db.productDetails.insert({"_id":1,"product_name": "Samsung S3","category": "mobiles","product_total": 5,"product_available": 3,"product_bought_by": [{"customer": "john","date": "7-Jan-2014"},{"customer": "mark","date": "8-Jan-2014"}]}
)
WriteResult({ "nInserted" : 1 })
>

在这份文件中,我们在product_bought_by字段中嵌入了购买产品的客户的信息。现在,每当有新客户购买产品时,我们将首先使用product_available字段检查该产品是否仍然可用。如果可用,我们将减少product_available字段的值,并在product_bought_by字段中插入新客户的嵌入式文档。我们将使用findAndModify命令来实现这一功能,因为它可以在同一时间内搜索和更新文档。

>db.products.findAndModify({ query:{_id:2,product_available:{$gt:0}}, update:{ $inc:{product_available:-1}, $push:{product_bought_by:{customer:"rob",date:"9-Jan-2014"}} }    
})

我们的嵌入式文档和使用findAndModify查询的方法确保了产品购买信息只有在产品可用时才会被更新。而整个交易都在同一个查询中,是原子性的。

与此相反,考虑一下这样的情况:我们可能把产品的可用性和谁购买了该产品的信息分开保存。在这种情况下,我们将首先使用第一个查询来检查产品是否可用。然后在第二个查询中,我们将更新购买信息。然而,有可能在这两个查询的执行过程中,有其他用户购买了该产品,而该产品已不再可用。在不知道这一点的情况下,我们的第二个查询将根据我们第一个查询的结果来更新购买信息。这将使数据库不一致,因为我们已经售出了一个不可用的产品。

高级索引

我们在名为用户的集合中插入了以下文件,如下图所示

db.users.insert({"address": {"city": "Los Angeles","state": "California","pincode": "123"},"tags": ["music","cricket","blogs"],"name": "Tom Benzamin"}
)

上述文件包含一个地址子文件和一个标签阵列。

阵列字段的索引
假设我们想根据用户的标签来搜索用户文档。为此,我们将在集合中的标签数组上创建一个索引。

在数组上创建索引又会为其每个字段创建单独的索引条目。所以在我们的例子中,当我们在tags数组上创建索引时,将为其值music、cricket和blogs创建单独的索引。

要在tags数组上创建一个索引,请使用以下代码

>db.users.createIndex({"tags":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
>

在创建索引之后,我们可以像这样在集合的tags字段上进行搜索

> db.users.find({tags:"cricket"}).pretty()
{"_id" : ObjectId("5dd7c927f1dd4583e7103fdf"),"address" : {"city" : "Los Angeles","state" : "California","pincode" : "123"},"tags" : ["music","cricket","blogs"],"name" : "Tom Benzamin"
}
>

要验证是否使用了正确的索引,请使用以下解释命令−

>db.users.find({tags:"cricket"}).explain()

这将给出以下结果−

{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "mydb.users","indexFilterSet" : false,"parsedQuery" : {"tags" : {"$eq" : "cricket"}},"queryHash" : "9D3B61A7","planCacheKey" : "04C9997B","winningPlan" : {"stage" : "FETCH","inputStage" : {"stage" : "IXSCAN","keyPattern" : {"tags" : 1},"indexName" : "tags_1","isMultiKey" : false,"multiKeyPaths" : {"tags" : [ ]},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"tags" : ["[\"cricket\", \"cricket\"]"]}}},"rejectedPlans" : [ ]},"serverInfo" : {"host" : "Krishna","port" : 27017,"version" : "4.2.1","gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e"},"ok" : 1
}
>

上述命令的结果是 "cursor":"BtreeCursor tags_1",这证实了正确的索引被使用。

对子文档字段进行索引
假设我们想根据城市、州和平码字段来搜索文件。由于所有这些字段都是地址子文件字段的一部分,我们将在子文件的所有字段上创建一个索引。

为了在子文档的所有三个字段上创建索引,请使用以下代码

>db.users.createIndex({"address.city":1,"address.state":1,"address.pincode":1})
{"numIndexesBefore" : 4,"numIndexesAfter" : 4,"note" : "all indexes already exist","ok" : 1
}
>

一旦建立了索引,我们就可以利用这个索引来搜索任何一个子文件字段,如下所示

> db.users.find({"address.city":"Los Angeles"}).pretty()
{"_id" : ObjectId("5dd7c927f1dd4583e7103fdf"),"address" : {"city" : "Los Angeles","state" : "California","pincode" : "123"},"tags" : ["music","cricket","blogs"],"name" : "Tom Benzamin"
}  

记住,查询表达式必须遵循指定的索引的顺序。因此,上面创建的索引将支持以下查询 -

>db.users.find({"address.city":"Los Angeles","address.state":"California"}).pretty()
{"_id" : ObjectId("5dd7c927f1dd4583e7103fdf"),"address" : {"city" : "Los Angeles","state" : "California","pincode" : "123"},"tags" : ["music","cricket","blogs"],"name" : "Tom Benzamin"
}
>

索引的局限性

额外的开销
每个索引都会占用一些空间,并在每次插入、更新和删除时造成开销。因此,如果你很少使用你的集合进行读取操作,不使用索引是有意义的。

内存的使用
由于索引被存储在RAM中,你应该确保索引的总大小不超过RAM的限制。如果总大小增加了RAM的大小,它将开始删除一些索引,导致性能损失。

查询限制
索引不能用于使用--的查询。

正则表达式或否定运算符,如$nin, $not, 等。
算术运算符,如$mod,等等。
$where条款
因此,建议你总是检查你的查询的索引使用情况。

索引键的限制
从2.6版本开始,如果现有的索引字段的值超过了索引键的限制,MongoDB将不会创建一个索引。

插入超过索引键限制的文档
如果任何文档的索引字段值超过了索引键限制,MongoDB将不会将该文档插入到一个有索引的集合。mongorestore和mongoimport工具的情况也是如此。

最大范围
一个集合不能有超过64个索引。
索引名称的长度不能超过125个字符。
一个复合索引最多可以有31个字段的索引。

相关文章:

MongoDB教程-7

正如在MongoDB关系的最后一章中所看到的,为了在MongoDB中实现规范化的数据库结构,我们使用了引用关系的概念,也被称为手动引用,在这个概念中,我们手动将被引用文档的id存储在其他文档中。然而,在一个文档包…...

Redisson提供优秀的并发控制机制

1. JDK集合类 对于JDK的集合类&#xff0c;forEach方法其实并不能完全避免并发修改异常。 forEach本质上还是一个循环遍历&#xff0c;如果在循环体内直接对集合进行修改&#xff0c;仍然会产生ConcurrentModificationException。 例如&#xff1a; List<String> lis…...

Linux: 设置qmake的Qt版本

Qt开发&#xff0c;qmake会对应一个Qt版本&#xff0c;有时候需要切换这个版本&#xff0c;例如把qmake从Qt5.12切换到Qt5.9, 怎么操作呢&#xff1f; 案例如下&#xff1a; 银河麒麟V10系统&#xff0c;下载安装了Qt5.9.8&#xff0c;但是检查qmake发现它使用的是5.12.8&…...

使用LLM插件从命令行访问Llama 2

大家好&#xff0c;最近的一个大新闻是Meta AI推出了新的开源授权的大型语言模型Llama 2&#xff0c;这是一项非常重要的进展。Facebook最初的LLaMA模型于今年2月发布&#xff0c;掀起了开源LLM领域的创新浪潮——从微调变体到从零开始的再创造。 如果在Llama 2版本发布之日&a…...

gateway过滤器没生效,特殊原因

看这边文章的前提&#xff0c;你要会gateway&#xff0c;知道过滤器怎么配置&#xff1f; 直接来看过滤器&#xff0c;局部过滤器 再来看配置 请求路径 http://127.0.0.1:8080/appframework/services/catalog/catalogSpecials.json?pageindex1&pagesize10&pkidd98…...

长相思追剧小游戏

看效果图 Vue长相思 刚学Vue&#xff0c;正好在追剧&#xff0c;看到这个小案例觉得挺好玩的&#xff0c;第一天学&#xff0c;代码太简陋了 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name&qu…...

leetcode做题笔记51

按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种…...

Windows同时安装两个版本的JDK并随时切换,以JDK6和JDK8为例,并解决相关存在的问题(亲测有效)

Windows同时安装两个版本的JDK并随时切换&#xff0c;以JDK6和JDK8为例&#xff0c;并解决相关存在的问题&#xff08;亲测有效&#xff09; 1.下载不同版本JDK 这里给出JDK6和JDK的百度网盘地址&#xff0c;具体安装过程&#xff0c;傻瓜式安装即可。 链接&#xff1a;http…...

【ChatGPT辅助学Rust | 基础系列 | Cargo工具】Cargo介绍及使用

文章目录 前言一&#xff0c;Cargo介绍1&#xff0c;Cargo安装2&#xff0c;创建Rust项目2&#xff0c;编译项目&#xff1a;3&#xff0c;运行项目&#xff1a;4&#xff0c;测试项目&#xff1a;5&#xff0c;更新项目的依赖&#xff1a;6&#xff0c;生成项目的文档&#xf…...

全面了解CPU Profiler:解读CPU性能分析工具的核心功能与用法

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、使用3.1 通过调用系统API3.2 通过Android Stu…...

rust format!如何转义{},输出{}?

在Rust中&#xff0c;如果你想要在字符串中包含花括号 {} &#xff0c;你需要使用双花括号 {{}} 来进行转义。这是因为单个花括号 {} 在字符串中表示占位符&#xff0c;用于格式化字符串。 以下是一个示例&#xff1a; fn main() {let text "这是一个示例&#xff1a; {…...

真人AI写真的制作方法-文生图换脸

AI写真最近火起来了&#xff0c;特别是某款现象级相机的出现&#xff0c;只需要上传自己的照片&#xff0c;就能生成漂亮的写真照&#xff0c;这一产品再次带火了AI绘画。今天我就来分享一个使用Stable Diffusion WebUI制作真人AI写真的方法&#xff0c;不用训练&#xff0c;快…...

vscode如何包含第三方库

方法1&#xff1a;使用C Extension 在include 的 rapidjson的头文件时&#xff0c;vscode会提示找不到的问题 悬停&#xff0c;点击黄色提示 Edit "includePath" setting Include Path&#xff0c;输入rapidjson的include路径 /Users/xxx/workspaces/rapidjson-1.1.…...

【Docker】Docker安装Consul

文章目录 1. 什么是Consul2. Docker安装启动Consul 点击跳转&#xff1a;Docker安装MySQL、Redis、RabbitMQ、Elasticsearch、Nacos等常见服务全套&#xff08;质量有保证&#xff0c;内容详情&#xff09; 1. 什么是Consul Consul是HashiCorp公司推出的开源软件&#xff0c;提…...

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(20)-Fiddler精选插件扩展安装让你的Fiddler开挂到你怀疑人生

1.简介 Fiddler本身的功能其实也已经很强大了&#xff0c;但是Fiddler官方还有很多其他扩展插件功能&#xff0c;可以更好地辅助Fiddler去帮助用户去开发、测试和管理项目上的任务。Fiddler已有的功能已经够我们日常工作中使用了&#xff0c;为了更好的扩展Fiddler&#xff0c…...

计算机top命令

top 快捷键 1 核心参数 1 1 参考资料 [1]. https://blog.csdn.net/weixin_45465395/article/details/115728520 [2].https://www.cnblogs.com/liushui-sky/p/13224762.html...

DevExpress WPF Tree List组件,让数据可视化程度更高!(二)

DevExpress WPF Tree List组件是一个功能齐全、数据感知的TreeView-ListView混合体&#xff0c;可以把数据信息显示为REE、GRID或两者的组合&#xff0c;在数据绑定或非绑定模式下&#xff0c;具有完整的数据编辑支持。 在上文中&#xff08;点击这里回顾DevExpress WPF Tree …...

lc1074.元素和为目标值的子矩阵数量

创建二维前缀和数组 两个for循环&#xff0c;外循环表示子矩阵的左上角&#xff08;x1,y1&#xff09;&#xff0c;内循环表示子矩阵的右下角&#xff08;x2,y2&#xff09; 两个for循环遍历&#xff0c;计算子矩阵的元素总和 四个变量&#xff0c;暴力破解的时间复杂度为O(…...

elementUi el-radio神奇的:label与label不能设置默认值

问题&#xff1a;最近项目遇到一个奇葩的问题&#xff1a;红框中列表的单选按钮无法根据需求设置默认选中&#xff0c;但是同样是设置开启状态的单选框可以设置默认状态 原因&#xff1a;开始同样是和开启/关闭状态一样也把红框中列表的默认值设置为数字模式&#xff0c;但是由…...

git仓库清理

关于git仓库的清理&#xff0c;主要就是清理git仓库里面的大的二进制文件。网上查了很多教程&#xff0c;很多都是用&#xff1a;git filter-branch.清理仓库中的大文件。 我尝试着本地测试了一下&#xff0c;发现是真慢呀。 方法一、git filter-branch step1&#xff1a;查…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...