在前面的博客中,咱们了解一些Mongodb中最基础的用法,只介绍了简单的增删查改,在这篇博客中,我将介绍一下稍微复杂一点的语法。html
在前面的博客中,咱们介绍了查找命令,其中能够指令多个查询条件,当全部条件都符合时,就能够查询到数据。那么,若是咱们只想只要有一个条件符合,就返回想要的数据,那么咱们应该怎么作呢?linux
db.getCollection('test_data_1').find({"字段1":"固定值1","字段2":"固定值2"})
在上面的命令中,其实是一个隐式的AND,由于须要同时知足。可是又没有出现AND这个关键词,因此被称为“隐式AND操做”。下面,就让咱们来将隐式转为显式,只须要使用“$and”便可。sql
db.getCollection('test_data_1').find( { "$and":[ {"字段1":"固定值1"}, {"字段2":"固定值2"} ] } )
or操做就是为了查询只符合其中任一条件的数据。命令语法和显式的AND操做同样。mongodb
db.getCollection('test_data_1').find( { "$or":[ {"字段1":"固定值1"}, {"字段2":"固定值2"} ] } )
其中,咱们须要知道,尽管存在隐式的AND操做,可是,对于OR操做来讲,不存在隐式的OR操做。 同时or操做时会遵循一个"短路原则":只要前面的条件知足了,那后面的条件直接跳过(相似编程中的||)。编程
下面即是一个嵌入式文档的例子:数组
咱们能够看到在studyInfo中,还有着score和project。其中,studyInfo被称为嵌入式文档,studyInfo下面的字段被称为嵌套字段app
下面是一个插入语句的示例。ide
db.getCollection('test_data_1').insertOne( { "age":18, "adress":"Hunan", "studyInfo":{ "score":59, "project":"LOL" } } )
查询语句函数
若是咱们须要根据嵌入式文档中的嵌套字段的条件去查询,那么下面这样使用就好了。若是嵌套字段里面还有嵌入式文档,一路点点点过去就好了。工具
db.getCollection('test_data_1').find( { "studyInfo.score":59 }, // 不返回studyInfo.score { "studyInfo.score":0 } )
在下面中,like字段保存的就是一个数组,因此咱们使用**[]**将"apple","orange","fruit"括起来。
db.getCollection('test_data_1').insertOne( { "name":"Array", "like":["apple","orange","fruit"] } )
使用Robo3T可视化工具查看,显示以下:
其中,like的类型为Array。可是若是咱们查询的时候须要根据like中某个值做为筛选目标的时候,咱们怎么办呢?咱们无需进行其余任何操做(和之前的查询如出一辙)。例如查询全部喜欢orange的人:
db.getCollection('test_data_1').find({"like":"orange"})
也就是说它的查询与之前没有任何区别。可是,既然是数组,总有必定其余的操做,例如查询字段数组为长度的记录:
db.getCollection('test_data_1').find({"like":{"$size":3}})
上面是查询like字段的数组长度为3的记录。
注意:“$size”只能查询某一个具体长度的数组,而不能查询范围,若是进行范围查询的话,会报错:
固然,既然有数组,那么必然会有索引,在mongodb中,数组的第一个元素的索引为0,和大部分的编程的状况是同样的。
咱们能够经过“字段名.索引”来定位元素。例如查询:
db.getCollection('test_data_1').find( { "like.0":"apple" } )
聚合的功能很简单,就是让Mongodb来处理数据,而后返回被处理好的数据。
聚合的操做命令是“aggregation”,基本格式是:
db.getCollection('test_data_1').aggregation([阶段1,阶段2,阶段3……])
集中,阶段能够为零个(那么就至关于findi命令),也能够为任意数量。其中,阶段中间有点相似linux或者unix中的管道
也就是说,前面一个阶段的输出,是后面一个结点的输入。
下面是来自菜鸟教程的一些关键字的用法。
下面我将在一些数据的处理方面来介绍一下其中的一些命令。
筛选数据的功能乍一看和find的功能差很少,而后仔细一看,还真的和find的功能如出一辙。筛选数据的关键字是“ $match”
db.getCollection('test_data_1').aggregate([{"$match":{和find彻底同样的过滤表达式}}])
下面是返回like字段数组的第一个元素为“apple”的记录(和上面数组字段里面查询返回的结果如出一辙)。
db.getCollection('test_data_1').aggregate([{"$match":{"like.0":"apple"}}])
那么,这样作有什么意义呢?返回的结果和find的命令同样,还比find麻烦,这样作岂不是画蛇添足。的确,若是咱们仅仅这样作,还不如使用find,它的强大之处在于与其余关键字进行组合。由于进行数据处理,通常第一步都是进行筛选。
前面咱们介绍了$project的介绍,那么修改字段咱们将使用$projecto来操做。
$project:修改输入文档的结构。能够用来重命名、增长或删除域,也能够用于建立计算结果以及嵌套文档。
正如上面所介绍的,$project的功能很强大,能够作到不少事情。
修改返回的字段
下面返回的字段中不包含_id和like 字段
db.getCollection('test_data_1').aggregate([ {"$project":{"_id":0,"like":0}} ])
下面是结合$match的使用,其中前面的$match的返回的输出是$project的输入
db.getCollection('test_data_1').aggregate([ {"$match":{"like":{"$size":3}}}, {"$project":{"_id":0,"like":0}} ])
这个的做用也和find中的返回返回部分字段的操做差很少,这个操做没有什么让人新奇的地方,下面将介绍它的其余强大之处。
注意事项
包括现有字段
_id
字段默认包含在输出文档中。- 若是指定包含文档中不存在的字段, $project 将忽略该字段包含,而且不会将该字段添加到文档中。
取消_id字段
- 默认状况下,
_id
字段包含在输出文档中。要从输出文档中排除_id
字段,必须在 $project 中明确指定对_id
字段的抑制。排除字段
若是指定排除某个或多个字段,则在输出文档中返回全部其余字段。
若是指定排除
_id
之外的字段,则不能使用任何其余 $project 规范表单:即,若是排除字段,则不能指定包含字段,重置现有字段的值或添加新字段。
添加新的字段
若是我想返回的结果中添加新的字段,怎么办?在project中直接添加就行
db.getCollection('test_data_1').aggregate([ {"$project":{ "name":1, "_id":0, // 添加的新的字段 "add":"GG" } } ])
不过值得注意的是:
若是指定排除
_id
之外的字段,则不能使用任何其余 $project 规范表单:即,若是排除字段,则不能指定包含字段,重置现有字段的值或添加新字段。
也就是说,若是排除了除“_id”之外的字段,那么,就GG了。就没办法添加字段了。
而且值得注意的是,添加新的字段的时候,若是旧的字段不设置为1,则不会返回。(也就是说,若是添加了新的字段,想要返回原本存在字段,必须将字段设置为1)
重命名字段
重命名字段和添加新的字段差很少,简单点来讲,咱们可使用“$旧的字段名”来表示字段的数据。示例以下
db.getCollection('test_data_1').aggregate([ {"$project":{ // 添加新的字段,新的字段的数据是name字段的数据 "add":"$name" } } ])
结果以下:
这个对于嵌套文档有着很是好的效果,能够看下面的两个例子
使用find | 使用聚合 |
---|---|
![]() |
![]() |
处理特殊字符
这里有说两个问题,若是我须要修改一个字段的数据为1,或者为$project呢?能够知道,这些值与mongodbe自身的语法冲突了(全部以“$”开头的普通字符串和数字都不能添加)。这个时候咱们可使用" $literal"关键字。
分组操做所对应的关键字是“$group”,它的做用是根据给出的字段key,它全部的key的值相同的记录放在一块儿进行运算。
在上一篇博客中使用了去重函数“distinct”,使用该函数后,返回的是一个数组。不过,如今咱们可使用“$group”去重。操做以下所示:
db.getCollection('test_data_1').aggregate( [ { "$group":{"_id":"$被g去重的字段名"} } ] )
其中,“_id”是必不可少的,不能用其余的去替代。而这个返回的也不是一个数组,而是不少条记录。
首先先说一下运算的关键字,关键字包括(来自菜鸟教程):
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中全部文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中全部文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不建立副本。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
你们看那个实例估计也明白怎么操做了。首先咱们先去重,而后再指定名字,最后进行计算:
计算的方法:{$关键字:$已有的字段名}
下面即是计算age的平均值,而后以“aver_age”返回。
原则上,“$sum”和“$avg”的值对应的值应该是数字,若是使用非数字,则“$sum”会返回0,“$avg”会返回“null”。注意,字符串是能够比较大小的。其中,“$sum”的值还可使用数字“1”,例如
"count":{"$sum":1}
,则返回的就是每一个分组有多少条记录。
拆分数组使用的关键字是“$unwind”,它的做用是把一条包含数组的记录拆分为很对条记录,其中,每一条记录拥有数组中的一个元素。
下面是数组like和infos进行拆分,其中拆分的结果数量是like数组的长度乘以infos数组的长度。
db.getCollection('test_data_1').aggregate( [ {"$unwind":"$like"}, {"$unwind":"$infos"}, ] )
Mongodb中的联集合查询相似SQL中的联表查询,在联集合查询中,有两个概念,主集合和被查集合。简单点来讲,就是主集合提供字段key,而后被查集合经过字段key查出须要的字段。
db.getCollection('主集合名').aggregate([ "$lookup":{ "from":"被查集合名", "localField":"主集合提供的字段key", "foreginField":"被查集合接受的字段", "as":"为查出来的字段命名", } ] )
下面是两个文档,一个为user,一个为login
如今咱们经过login中的id从user中拿出字段:
db.getCollection('login').aggregate([ { "$lookup":{ "from":"user", "localField":"loginId", "foreignField":"id", "as":"login_name", } } ] )
返回结果以下:
其中,login_name为联结合查出来的数据,为一个数组。
固然,对于这个结果的样式咱们是不太满意的,由于我咱们只想拿出name,这个时候咱们就须要使用前面的知识来解决这个问题了。
db.getCollection('login').aggregate([ { "$lookup":{ "from":"user", "localField":"loginId", "foreignField":"id", "as":"login_name", } }, { "$unwind":"$login_name" }, { "$project":{ "_id":0, "loginId":1, "name":"$login_name.name" } } ])
返回的结果如图所示:
参考书籍:《左手Mongodb,右手Redis》
菜鸟教程:https://www.runoob.com/mongodb/mongodb-tutorial.html
docs4dev:https://www.docs4dev.com/docs/zh/mongodb/v3.6/reference