1. 前言
前几篇,老玩家绕道即可,新手晚上闲着也是蛋疼,不如把命令敲一边,这样你就会对MongoDB有一定的掌握啦。如果没有安装MongoDB去看我的上一篇博客 MongoDB下载安装与简单增删改查
前奏:启动mongdb数据库服务,并进入shell界面
> mongo --进入shell界面
2. 常用命令
> show dbs -- 查看数据库列表
> use admin --创建admin数据库,如果存在admin数据库则使用admin数据库
> db ---显示当前使用的数据库名称
> db.getName() ---显示当前使用的数据库名称
> db.dropDatabase() --删当前使用的数据库
> db.repairDatabase() --修复当前数据库
> db.version() --当前数据库版本
> db.getMongo() --查看当前数据库的链接机器地址
> db.stats() 显示当前数据库状态,包含数据库名称,集合个数,当前数据库大小 ...
> db.getCollectionNames() --查看数据库中有那些个集合(表)
> show collections --查看数据库中有那些个集合(表)
> db.person.drop() --删除当前集合(表)person
3. MongoDB接入Javascrip风格语法,for,while,next,hasNext,forEach,toArray,findOne,limit
> db.getCollectionNames()
[ "papers", "person", "persons", "products" ]
> p={name:"张龙豪", age:18}
{ "name" : "张龙豪", "age" : 18 }
> db.person.insert(p)
WriteResult({ "nInserted" : 1 })
> db.person.save(p)
WriteResult({ "nInserted" : 1 })
> db.person.find()
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
>
Note:
1、p={name:“张龙豪”,age:18} 这个不是规范的json格式,使用这种类似javascript语法,对象会自动补全为规范的json格式{“name”:“张龙豪”,“age”:18}.
2、我在这里插入2条数据,一条是insert语法,一条是save语法,这里的insert与save是一样的功能。
> for(var i=1;i<5;i++) db.person.insert({"name":"张龙豪"+i,"age":i});
WriteResult({ "nInserted" : 1 })
> db.person.find()
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc7"), "name" : "张龙豪3", "age" : 3 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc8"), "name" : "张龙豪4", "age" : 4 }
>
Note:这里我主要用啦一个for语法,循环插入啦4条数据,是不是有点小激动。哈哈,mongodb就是这么任性。
> var cursor = db.person.find();
> while(cursor.hasNext()) printjson(cursor.next())
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc7"), "name" : "张龙豪3", "age" : 3 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc8"), "name" : "张龙豪4", "age" : 4 }
>
Note:这里是吧查询出来的
1、while:作为程序员应该都不陌生他是个循环。
2、hasNext: cursor集合遍历,是否还有数据。
3、printjson:输出集合中的文档
4、next:当前文档,并向下遍历。
> db.person.find().forEach(printjson);
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc7"), "name" : "张龙豪3", "age" : 3 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc8"), "name" : "张龙豪4", "age" : 4 }
>
Note:forEach循环输入,必须定义一个函数供每个游标元素调用。
> var cursor = db.person.find()
> printjson(cursor[5])
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc8"), "name" : "张龙豪4", "age" : 4 }
> printjson(cursor[3])
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
>
Note:游标也可以当作数组来用。
> var arr = db.person.find().toArray();
> arr[3]
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
>
Note:游标转换为真实的数组类型,使用。
> db.person.findOne({"name":"张龙豪"})
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
> db.person.find().limit(3)
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
>
Note:findOne,返回结果集中的第一条数据。limit(3),返回结果集中的前三条数据。
4. MongoDB中的高级查询
面向文档的NoSql数据库重要解决的问题不是高性能的并发读写问题,而是保证海量数据存储的同时,具有比一般数据库更加良好的查询性能。
4.1 指定需要返回的键
有时并不需要将文档中所有键/值对都返回。遇到这种情况,可以通过 find (或者findOne) 的第二个参数来指定想要的键。这样既会节省传输的数据量,又能节省客户端解码文档的时间和内存消耗。
例如,如果只对用户集合的 “username” 和 email 键感兴趣,可以使用如下查询返回这些键:
> db.users.find({}, {"username": 1, "email": 1})
{
"_id": ObjectId("4ba0f0dfd22aa494fd523620"),
"username": "joe",
"email": "joe@example.com"
}
可以看到,默认情况下 “_id” 这个键总是被返回,即便是没有指定要返回这个键。
也可以用第二个参数来剔除查询结果中的某些键/值对。例如,文档中有很多键,但是我们不希望结果中含有 "fatal_weakness"键:
db.users.find({}, {"username" : 1, "_id" : 0})
使用这种方式,也可以把 “_id” 键剔除掉:
> db.users.find({}, {"username" : 1, "_id" : 0})
{
"username" : "joe"
}
4.2 OR 查询
MongoDB 中有两种方式进行 OR 查询:“ i n " 可 以 用 来 查 询 一 个 键 的 多 个 值 , " in" 可以用来查询一个键的多个值," in"可以用来查询一个键的多个值,"or” 更通用一些,可以在多个键中查询任意的给定值。
如果一个键需要与多个值进行匹配的话,就要用到 “$in” 操作符,再加一个条件数组。例如,抽奖活动的中奖号码是 725、542 和 390。要找出全部的中奖文档的话,可以构建如下查询:
> db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})
“ i n " 能 对 单 个 键 做 O R 查 询 , 但 要 是 想 找 到 " t i c k e t n o " 为 725 或 者 " w i n n e r " 为 t r u e 的 文 档 该 怎 么 办 呢 ? 对 于 这 种 情 况 , 应 该 使 用 " in" 能对单个键做 OR 查询,但要是想找到 "ticket_no" 为 725 或者 "winner" 为 true 的文档该怎么办呢?对于这种情况,应该使用 " in"能对单个键做OR查询,但要是想找到"ticketno"为725或者"winner"为true的文档该怎么办呢?对于这种情况,应该使用"or” 。
> db.raffle.find({"$or" : [{"ticket_no" : "725"}, {"winner" : true}])
“$or” 可以包含其他条件。例如,如果希望匹配到中奖的 “ticket_no”,或者 “winner” 键的值为 true 的文档,就可以这么做:
> db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}},
{"winner" : true}]})
4.3 特定类型的查询
4.3.1 null
null 类型的行为有点奇怪。他确实能匹配自身,所以要是有一个包含如下文档的集合:
> db.c.find()
{"_id" : "1", "y" : null}
{"_id" : "2", "y" : 1}
{"_id" : "3", "y" : 2}
就可以按照预期的方式查询 “y” 键为 null 的文档:
> db.c.find({"y" : null})
{"_id" : "1", "y" : null}
但是,null 不仅会匹配某个键的值为 null 的文档,而且还会匹配不包含这个键的文档。所以,这种匹配还会返回缺少这个键的所有文档:
> db.c.find({"z" : null})
{"_id" : "1", "y" : null}
{"_id" : "2", "y" : 1}
{"_id" : "3", "y" : 2}
如果仅想匹配键值为 null 的文档,既要检查该键的值是否为 null,还要通过 “$exists” 条件判定键值已存在:
> db.c.find({"z" : {"$in" : [null], "$exists" : true}})
4.3.2 查询数组
- $all 操作符
a l l 匹 配 所 有 , 类 似 t − s q l 中 的 i n , 但 是 t − s q l 中 的 i n 是 满 足 括 号 里 面 的 任 何 一 个 都 能 出 数 据 , 而 m o n g o d b 中 的 all匹配所有,类似t-sql中的in,但是t-sql中的in是满足括号里面的任何一个都能出数据,而mongodb中的 all匹配所有,类似t−sql中的in,但是t−sql中的in是满足括号里面的任何一个都能出数据,而mongodb中的all则必须满足[]中的所有值。
> var p = {name:"Tom",age:[7,8,9,10],wife:"Jerry"}
> db.person.save(p)
WriteResult({ "nInserted" : 1 })
> db.person.find({age:{$all:[7,9]}})
{ "_id" : ObjectId("5e3f7fb6b3db76a386695bc9"), "name" : "Tom", "age" : [ 7, 8, 9, 10 ], "wife" : "Jerry" }
> db.person.find({age:{$all:[7,19]}})
>
{age:{$all:[7,9]}}:age数组中只要有7和9就满足条件。如果只有7,没有9则不符合条件。
- $in
i n 包 含 , in包含, in包含,nin不包含。跟t-sql中的in,not in一样。
> db.person.find({age:{$in:[10,11]}})
{ "_id" : ObjectId("5e3f7fb6b3db76a386695bc9"), "name" : "Tom", "age" : [ 7, 8, 9, 10 ], "wife" : "Jerry" }
>
{age:{$in:[10,11]}} : 如果age是数组的话,只要数组包含in中条件的任何一条数据,都能被检索出来。不是数组,则只要满足in中的任何一个条件数据,也可以被检索出来。
- $size
数组元素个数。
> db.person.find({age:{$size:4}})
{ "_id" : ObjectId("5e3f7fb6b3db76a386695bc9"), "name" : "Tom", "age" : [ 7, 8, 9, 10 ], "wife" : "Jerry" }
>
{age:{$size:4}}: age数组元素个数为4的数据结果集。
- $slice 操作符
前面已经提及, find 的第二个参数是可选的,可以指定需要返回的键。这个特别的 “$slice” 操作符可以返回某个键匹配的数组元素的一个子集。
# 返回前10条评论
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : 10}})
# 返回最后10条评论
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -10}})
“$slice” 也可以指定偏移值以及希望返回的元素数量,来返回元素集合中间位置的某些结果:
# 跳过前23个元素,返回第 24 ~ 33 个元素
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : [23, 10]}})
除非特别声明,否则使用 “$slice” 时将返回文档中的所有键。与别的键说明符不返回未提及的键有点不太一样。
有如下文章及评论数据:
> db.blog.posts.findOne()
{
"id" : "122",
"title" : "A blog post",
"content" : "...",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post."
},
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post."
}
]
}
用 “$slice” 来获取最后一条评论,可以这样:
> db.blog.posts.findOne({}, {"comments" : {"$slice" : -1}})
{
"_id" : ObjectId("5e4002d6b3db76a386695bcb"),
"id" : "122",
"title" : "A blog post",
"content" : "...",
"comments" : [
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post."
}
]
}
>
title 和 content 都返回了,即便没有显式地出现在说明符中。
当我们不知道元素的下标时,可以使用 $ 操作符得到一个匹配的元素。对于上面的示例,可以用如下的方式得到 Bob 的评论:
> db.blog.posts.findOne({"comments.name" : "bob"}, {"comments.$" : 1})
{
"_id" : ObjectId("5e4002d6b3db76a386695bcb"),
"comments" : [
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post."
}
]
}
>
注意:这样只会返回第一个匹配的文档。只有 “comments” 数组中的第一条评论会被返回。 除了 comments 属性和 _id 属性,其它属性都不会返回
- 数组和范围查询的相互作用
对于下面的文档,找出 “x” 键的值位于 10 和 20 之间的所有文档。
{"x" : 5 }
{"x" : 15 }
{"x" : 25 }
{"x" : [ 5, 25 ] }
使用 db.test.find({“x” : {“ g t " : 10 , " gt" : 10, " gt":10,"lt” : 20}}) 去查询,期望的返回的文档是 {“x” : 15},但是却返回了两个文档。
> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}})
{ "_id" : ObjectId("5e40082db3db76a386695bcd"), "x" : 15 }
{ "_id" : ObjectId("5e40082db3db76a386695bcf"), "x" : [ 5, 25 ] }
>
这是因为 25 与查询条件中的第一个语句(大于10)相匹配,5 与查询条件中的第二个语句(小于20)相匹配。
这使对数组使用范围查询没有用:范围会匹配任务多元素数组。可以使用 “$elemMatch” 可以使用多个查询条件对一个数组元素进行匹配。
> db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}}})
> db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 26}}})
{ "_id" : ObjectId("5e40082db3db76a386695bcf"), "x" : [ 5, 25 ] }
>
4.3.3 查询嵌套文档
假设有博客文章若干,要找到由 Joe 发表的 5 分以上的评论。博客文章的结构如下所示:
> db.blog.posts.findOne()
{
"_id" : ObjectId("5e4002d6b3db76a386695bcb"),
"title" : "A blog post",
"content" : "...",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post.",
"score" : 3
},
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post.",
"socre" : 6
}
]
}
>
不能直接使用 db.blog.posts.find({“comments” : {“name” : “joe”, “score” : {“KaTeX parse error: Expected 'EOF', got '}' at position 9: gte" : 5}̲}}) 来找寻。内嵌文档的匹配…gte” : 5}}) 也不行,因为符合 name 条件的评论和符合 score 条件可能不是同一条评论。
可以使用 “$elemMatch” 来正确匹配数组的一组条件。
> db.blog.posts.find({"comments" : {"$elemMatch" : {"name" : "joe", "score" : {"$gte" : 5}}}})
> db.blog.posts.find({"comments" : {"$elemMatch" : {"name" : "joe", "score" : {"$gte" : 3}}}})
{ "_id" : ObjectId("5e4002d6b3db76a386695bcb"), "title" : "A blog post", "content" : "...", "comments" : [ { "name" : "joe", "email" : "joe@example.com", "content" : "nice post.", "score" : 3 }, { "name" : "bob", "email" : "bob@example.com", "content" : "good post.", "score" : 6 } ] }
>
4.4 其它查询
> db.person.find({"age":{$gt:17}})
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
> db.person.find({"age":{$lt:2}})
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
> db.person.find({"age":{$gte:18}})
{ "_id" : ObjectId("5e3f75cfb3db76a386695bc3"), "name" : "张龙豪", "age" : 18 }
{ "_id" : ObjectId("5e3f75d6b3db76a386695bc4"), "name" : "张龙豪", "age" : 18 }
> db.person.find({"age":{$lte:1}})
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
> db.person.find({"age":{$gt:16,$lt:18}})
> db.person.find({"age":{$gt:1,$lt:3}})
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
>
Note:条件操作符号: > 、 < 、 >= 、<=
- g t / / 大 于 > , gt //大于 > , gt//大于>,lt //小于 < , g t e / / 大 于 等 于 > = , gte //大于等于 >= , gte//大于等于>=,lte //小于等于
- {“filed”:{KaTeX parse error: Expected 'EOF', got '}' at position 9: op,value}̲} //filed字段 ,op条件操作符号,value值。
- {“age”:{$gt:1}} : person集合中年龄大于1的所有数据文档
- $exists 判断字段是否存在
> var p = {name:"Jim", age:8, city:"usa"}
> db.person.save(p)
WriteResult({ "nInserted" : 1 })
> db.person.find({city:{$exists:true}})
{ "_id" : ObjectId("5e3f8041b3db76a386695bca"), "name" : "Jim", "age" : 8, "city" : "usa" }
>
{city:{$exists:true}}: 集合中存在city这个字段的数据
- $mod 取模运算
> db.person.find({age:{$mod:[7,1]}})
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
{ "_id" : ObjectId("5e3f7fb6b3db76a386695bc9"), "name" : "Tom", "age" : [ 7, 8, 9, 10 ], "wife" : "Jerry" }
{ "_id" : ObjectId("5e3f8041b3db76a386695bca"), "name" : "Jim", "age" : 8, "city" : "usa" }
>
{age:{$mod:[7,1]}}:集合中模7余1的数据
- $ne不等于
> db.person.find({name:{$ne:"张龙豪"}})
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc5"), "name" : "张龙豪1", "age" : 1 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc6"), "name" : "张龙豪2", "age" : 2 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc7"), "name" : "张龙豪3", "age" : 3 }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc8"), "name" : "张龙豪4", "age" : 4 }
{ "_id" : ObjectId("5e3f7fb6b3db76a386695bc9"), "name" : "Tom", "age" : [ 7, 8, 9, 10 ], "wife" : "Jerry" }
{ "_id" : ObjectId("5e3f8041b3db76a386695bca"), "name" : "Jim", "age" : 8, "city" : "usa" }
>
- $not
> db.person.find({name:{$not:/^张.*/}})
{ "_id" : ObjectId("5e3f7fb6b3db76a386695bc9"), "name" : "Tom", "age" : [ 7, 8, 9, 10 ], "wife" : "Jerry" }
{ "_id" : ObjectId("5e3f8041b3db76a386695bca"), "name" : "Jim", "age" : 8, "city" : "usa" }
>
$not正则匹配,不包含以张开头的数据。
db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}})
“$not” 后面也可以包含其它条件。
- skip,limit,sort,count
> db.person.find().skip(3).limit(2).sort({age:-1})
{ "_id" : ObjectId("5e3f8041b3db76a386695bca"), "name" : "Jim", "age" : 8, "city" : "usa" }
{ "_id" : ObjectId("5e3f77b3b3db76a386695bc8"), "name" : "张龙豪4", "age" : 4 }
>
- skip(2):从数据集的第二条开始查询
- limit(2) : 依次查出2条数据。
- sort({age:1}) : 1.正序查询,-1倒叙查询。
- count():结果集总数。
本文转自:MongoDB高级查询详细