千家信息网

MongoDB高级语法

发表于:2024-10-08 作者:千家信息网编辑
千家信息网最后更新 2024年10月08日,and操作:隐式and操作:db.getCollection("the_table").find({"age":{"$gt":20},"sex":"男"}) //对age与sex这两个字段的查询条件需
千家信息网最后更新 2024年10月08日MongoDB高级语法

and操作:

隐式and操作:

db.getCollection("the_table").find({"age":{"$gt":20},"sex":"男"}) //对age与sex这两个字段的查询条件需要同时满足

显式and操作:

db.getCollection("the_table").find({"$and":[{"age":{"$gte":20}},{"address":"里世界"}]})

显式、隐式混用:

db.getCollection("the_table").find({
"id":{"$lt": 10},
"$and": [{"age": {"$gt": 20}}, {"sex": "男"}]
})

不能写成隐式and操作的例子:

db.getCollection("the_table").find({
"$and": [
{"$or": [{"age": {"$gt": 28}}, {"salary": {"$gt": 9900}}]},
{"$or": [{"sex": "男"}, {"id": {"$lt": 20}}]}
]
})

or操作:

年龄大于28,或工资大于9900的:

db.getCollection("the_table").find({
"$or": [{"age": {"$gt": 28}},{"salary":{"$gt": 9900}}]
})

(注意:mongodb在执行or操作时会遵循一个"短路原则":只要前面的条件满足了,那后面的条件直接跳过。如果age大于28 ,那就不需要去检查salary的值是多少。只有在age不满足查询条件时,才会去检查salary的值)

OR操作一定是显式的,不存在隐式的OR操作

而这里去可以把or两边的都显示出来:

> db.getCollection("the_table").find()
......
{ "_id" : ObjectId("5d10400adc4728bc5f52f3ca"), "username" : "张三" }
{ "_id" : ObjectId("5d104011dc4728bc5f52f3cb"), "username" : "李四" }
> db.getCollection("the_table").find({"$or":[{"username":"张三"},{"username":"李四"}]})
{ "_id" : ObjectId("5d10400adc4728bc5f52f3ca"), "username" : "张三" }
{ "_id" : ObjectId("5d104011dc4728bc5f52f3cb"), "username" : "李四" }
>



嵌入式文档的查询:

嵌入字段只是定位的时候多了一步。除此之外,嵌入字段和普通字段没有区别。

查询所有followed大于10的数据:

db.getCollection("the_table").find({"user.followed": {"$gt": 10}})

如需要在返回的查询结果中只显示嵌入式文档中的部分内容,也可以使用点号来实现。例如只返回"name"和"user_id"这两个字段,查询语句:

db.getCollection("the_table").find(
{"user.followed": {"$gt": 10}},
{"_id": 0, "user.name": 1, "user.user_id": 1}
)



包含与不包含:

查出所有size包含M的数据:

db.getCollection("the_table").find({"size": "M"})

查出所有size不包含M的数据:

db.getCollection("the_table").find({"size": {"$ne": "M"}})

数组中有元素在另一个范围空间内:

db.getCollection("the_table").find({"price": {"$lt": 300, "$gt": 200}}



数组应用:

根据数组长度查询数据:

从数据集the_table中查询所有price长度为2的记录:

db.getCollection("the_table").find({"price": {"$size": 2}})

根据索引查询数据(索引是从0 开始的)

查询所有" size "的第1个(索引为0)数据为" S "的记录,查询语句为:

db.getCollection("the_table").find({"size.0": "S"})

使用索引也可以比较大小。例如,查询"price "第1 个数据大于500 的所有记录:

db.getCollection("the_table").find({"price.0": {"$gt": 500}})



高级更新:

最好用$push或$addToSet,这两个命令都是往数组中添加数据,但$addToSet是唯一的,阻止了重复数据

db.getCollection("the_table").update(
{"favorites.movies": "Cassablanca"},
{"$addToSet": {"favorites.movies": "the maltese falcon"}},
false,
true
)

第一个参数:匹配电影列表中包含Cassablanca的用户

第二个参数:使用$addToSet添加the maltese falcon到列表中

第三个参数:false,控制是否允许upsert。这个命令告诉更新操作,当一个文档不存在的时候是否插入它,这取决于更新操作是操作符更新还是替换更新

第四个参数:true,表示是否更新多个更新。默认情况下,mongodb更新只针对第一个匹配文档。如果想更新所有匹配文档,就必须显示指定这个参数。


删除数据:

db.user.remove({"favorites.cities":"Cheyenne"})

注意:remove()操作不会删除集合,它只会删除集合中的某个文档。我们可以把它和sql中的delete命令类比。如果要删除集合以及附带的索引数据,可以用drop()方法:

db.user.drop()


MongoDB的聚合查询:

使用聚合功能,可以直接让MongoDB来处理数据。聚合功能可以把数据像放入传送带一样,先把原始数据按照一定的规则进行筛选处理,然后通过多个不同的数据处理阶段来处理数据,最终输出一个汇总的结果。

聚合操作的命令为"aggregate",基本格式为:collection.aggregate([阶段1,阶段2,阶段3, ……,阶段N])

聚合操作可以有0 个、l 个或者多个阶段。如果有0 个阶段,则查询命令写为:collection.aggregate()。那么它的作用和collection.find() 一样

如果聚合有至少一个阶段,那么每一个阶段都是一个字典。不同的阶段负责不同的事情,每一个阶段有一个关键字。有专门负责筛选数据的阶段" $match '3 ,有专门负责宇段相关的阶段" $pr句ect",有专门负责数据分组的阶段"$group"等。聚合操作有几十个不同的阶段关键字

一般情况下,并非所有的数据都需要被处理,因此大多数时候聚合的第一个阶段是数据筛选。就像find()一样,把某些满足条件的数据选出来以便后面做进一步处理。数据筛选的关键字为$match,它的用法为:collection.aggregate([{"$match":{和find 完全一样的查询表达式}}])


从the_table数据集中,查询age大于等于27,且sex为"女"的所有记录:

db.getCollection("the_table").aggregate([
{"$match": {"age": {"$gte": 27}, "sex": "女"}}
])

从查询结果来看,这一条聚合查询语句的作用完全等同于:
db.getCollection("the_table").find({"age": {"$gte": 27}, "sex": "女"})

这两种写法,核心查询语句{"age": {"$gte": 27} , "sex":"女"}完全一样。聚合查询操作中的{"$match":{和find完全一样的查询表达式}}","$match"作为一个字典的Key,字典的Value和"find()"第1个参数完全相同。"find()"第1个参数能怎么写,这里就能怎么写。

例如,查询所有age大于28或sex为男的记录,聚合查询可以写为:

db.getCollection("the_table").aggregate([
{"$match": {"$or": [{"age": {"$gt": 28}}, {"sex": "男"}]}}
])

从效果上看,使用聚合查询与直接使用"自nd()" 效果完全相同,而使用聚合查询还要多敲几次键盘,那它的好处在哪里呢?聚合操作的好处在于" 组合" 。接下来会讲到更多的聚合关键字,把这些关键字组合起来才能体现出聚合操作的强大。


筛选与修改字段:

$project来实现一个己经有的功能一一只返回部分字段(这里的字段过滤语句与find()第2个参数完全相同)

db.getCollection("the_table").aggregate([
{"$project": {"_id":0, "sex":1, "age":1}}
])

先筛选记录,再过滤字段:

db.getCollection("the_table").aggregate([

{"$match": {"age": {"$gt": 28}}}

{"$project": {"_id":0, "sex":1, "age":1}},
])


添加新字段:

db.getCollection("the_table").aggregate([
{"$project": {"_id":0, "sex":1, "age":1, "newfield": "hello world"}},
{"$match": {"age": {"$gt": 28}}}
])

(newfield是原来没有的字段)

复制现有字段:

db.getCollection("the_table").aggregate([
{"$match": {"age": {"$gt": 28}}},
{"$project": {"_id":0, "sex":1, "age":1, "newfield": "$age"}}
])

修改现有字段的数据:

db.getCollection("the_table").aggregate([
{"$match": {"age": {"$gt": 28}}},
{"$project": {"_id":0, "sex":1, "age":1, "newfield": "this is new field"}}
])


注意:这并不会改变数据库里的数据,只是改变输出的数据

(数据并没有变化)


抽取嵌套字段:

上面的:添加新字段、复制现有字段、修改现有字段的数据等,看起来并没有卵用,而下面的例子就有用了:

如果用find(),想返回user_id和name,则查询语句为:

db.getCollection("the_table").find({},{"user.name":1, "user.user_id":1})

返回结果为:

(显然,嵌套字段处理起来并不方便)

现在用$project将嵌套字段中的内容抽取:

db.getCollection("the_table").aggregate([
{"$project": {"name":"$user.name", "user_id":"$user.user_id"}}
])


处理字段特殊值:

• 如果想添加一个字段,但是这个字段的值就是数字" 1 "会怎么样?
• 如果添加一个字段,这个字段的值就是一个普通的字符串,但不巧正好以"$"开头,又会怎么样呢?

关键字:$literal

db.getCollection("the_table").aggregate([
{"$match": {"age": {"$gt": 28}}},
{"$project": {"_id":0, "id":1, "hello": {"$literal":"$normalstring"}, "abcd":{"$literal":1}}}
])


分组操作:

去重的格式:db.getCollection("the_table").aggregate([{"$group": {"_id": "$被去重的字段名"}}])

db.getCollection("the_table").aggregate([
{"$group": {"_id": "$name"}}
])

分组操作虽然也能实现去重操作,但是它返回的数据格式与distinct函数是不一样的。distinct函数返回的是数组,而分组操作返回的是几条记录

去重并统计:

db.getCollection("the_table").aggregate([
{"$group": {"_id": "$name","max_age":{"$max":"$age"},"min_age":{"$min":"$age"},"avg_age":{"$avg":"$age"},"sum_age":{"$sum":"$age"}}}
])

原则上,$sum和$avg的值对应的字段的值应该都是数字。如果强行使用值为非数字的字段,那么$sum会返回0, $avg会返回null。而字符串是可以比较大小的,所以,$max与$min可以正常应用到字符串型的字段

还可以使用$sum的值为数字1来统计多少条记录:

db.getCollection("the_table").aggregate([
{"$group": {"_id": "$name","doc_count":{"$sum":1},"max_age":{"$max":"$age"},"min_age":{"$min":"$age"},"avg_age":{"$avg":"$age"},"sum_age":{"$sum":"$age"}}}
])


分组/去重、最新一条数据:

db.getCollection("the_table").aggregate([
{"$group": {"_id": "$name","age":{"$last":"$age"},"address":{"$last":"$address"}}}
])

可以取最新的数据,自然可以取最早的数据:

db.getCollection("the_table").aggregate([
{"$group": {"_id": "$name","age":{"$first":"$age"},"address":{"$first":"$address"}}}
])


拆分数组(用关键字:$unwind):

格式:collection.aggregate([{"$unwind":"$字段名"}])

db.getCollection("the_table").aggregate([
{"$unwind":"$size"}
])

还可以把price数组也拆分:

db.getCollection("the_table").aggregate([
{"$unwind":"$size"},
{"$unwind":"$price"}
])



联集合查询:

主集合.aggregate([
{
"$lookup": {
"from": "被查集合名",
"localField": "主集合的字段",
"foreignField": "被查集合的字段",
"as": "保存查询结果的字段名"
}
}
])

其中的"主集合"与"被查集合"需要搞清楚。如果顺序搞反了, 则结果会不同。
例如, 现在需要在做博集合中查询用户信息, 那么主集合就是微博集合, 被查集合就是用户集合。于是查询语句可以写为以下:

db.getCollection("example_post").aggregate([
{"$lookup":{
"from": "example_user",
"localField": "user_id",
"foreignField": "id",
"as": "user_info"
}}
])

(这里user_info字段之所以会是一个数组,是因为被查询集合中可能有多条记录都满足条件,只有使用数组才能把它们都保存下来。由于用户集合每一个记录都是唯一的,所以这个数组只有一个元素)

联集合查询并美化结果:

db.getCollection("example_post").aggregate([
{"$lookup":{
"from": "example_user",
"localField": "user_id",
"foreignField": "id",
"as": "user_info"
}},
{"$unwind":"$user_info"}
])

当然,还可以将联集合查询拆分结果返回特定内容:

db.getCollection("example_post").aggregate([
{"$lookup":{
"from": "example_user",
"localField": "user_id",
"foreignField": "id",
"as": "user_info"
}},
{"$unwind":"$user_info"},
{"$project":{
"content": 1,
"post_time": 1,
"name": "$user_info.name",
"work": "$user_info.work"
}}
])

以用户为基准联集合查询:

db.getCollection("example_user").aggregate([
{"$lookup":{
"from": "example_post",
"localField": "id",
"foreignField": "user_id",
"as": "weibo_info"
}},
{"$unwind":"$weibo_info"},
{"$project":{
"name": 1,
"work": 1,
"content": "$weibo_info.name",
"post_time": "$weibo_info.work"
}}
])



还可以指定只查某人的:

db.getCollection("example_user").aggregate([
{"$match": {"name": "张三疯"}},
{"$lookup":{
"from": "example_post",
"localField": "id",
"foreignField": "user_id",
"as": "weibo_info"
}},
{"$unwind":"$weibo_info"},
{"$project":{
"content": 1,
"post_time": 1,
"name": "$weibo_info.name",
"work": "$weibo_info.work"
}}
])

(从性能上讲,建议把$match放在最前面,这样可以充分用到mongodb的索引)

数据 查询 字段 阶段 数组 更新 参数 结果 处理 关键 关键字 语句 文档 条件 索引 不同 命令 用户 分组 就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 滴滴网络安全审查视频 2019注册软件开发公司 服务器渲染 前端渲染 网络技术基础课个人总结 加强国家网络安全管理 批量附加数据库工具中文官方版 数据库的参考文献2020 我的世界服务器白名单是什么意思 江阴软件开发诚信合作 数据库pga为多少 cnki中国知网数据库 服务器多网卡路由配置 清理手机网络安全的app 美食专家数据库修复工具 加强网络安全教室需要怎么做 法院网络安全自查总结报告 帝王阁服务器 服务器搭建多个系统 学计算机怎么下软件开发 关注粉丝数据库设计 舆情分析和网络安全模式 网络安全工程师面试经验 暗墨我的世界的服务器是什么 宿迁市场软件开发推荐咨询 安全纳入软件开发全生命周期 数据库安全系统排行 郧阳区正规软件开发品质保障 中科曙光服务器是否为国产化设备 枣庄市网络安全执法案例 网络技术实训论文1500字
0