db.xxx.find
使用
在MySql,会对>大于),<(小于),=(等于)这些东西很熟悉,但是在db中会有区别,我们会用如下:
小于($lt)
:英文全称less-than
小于等于($lte)
:英文全称less-than-equal
大于($gt)
:英文全称greater-than
大于等于($gte)
:英文全称greater-than-equal
不等于($ne)
:英文全称not-equal 我们现在要查找一下,公司内年龄小于30大于25岁的人员。
_id
不显示id
db.workmate.find(
{age: { $lte: 30, $gte: 25 }},
{name:true, age:true, "skill.skillOne": true, _id: false}
);
日期查找
MongoDB也提供了方便的日期查找方法现在我们要查找注册日期大于2018年1月10日的数据
var startDate = new Date('01/01/2018');
db.workmate.find(
{regeditTime: {$gt: startDate}},
{name:true, age:true, "skill.skillOne": false}
);
//查找age < 20
db.workmate.find( {age: {$lt: 20}}, {name:true, age:true, "skill.skillOne": true, _id:false} );
//查找age <= 20
db.workmate.find( {age: {$lte: 20}}, {name:true, age:true, "skill.skillOne": true, _id:false} );
//查找age == 20
db.workmate.find( {age: 20}, {name:true, age:true, "skill.skillOne": true, _id:false} );
//查找age > 20
db.workmate.find( {age: {$gt: 20}}, {name:true, age:true, "skill.skillOne": true, _id:false} );
//查找age >= 20
db.workmate.find( {age: {$gte: 20}}, {name:true, age:true, "skill.skillOne": true, _id:false} );
find的多条件查询
很多时候我们需要查询的值不只是有一个简单的条件,比如我们现在要查询一下同事中是33岁和25岁的,还比如我们要查询同事中大于30岁并且会PHP技能的。MongoDB在这方面也支持的很好.
$in修饰符
in修饰符可以轻松解决一键多值的查询情况。
于$in
相对的修饰符是$nin
//$in修饰符 >=a <=b a<b
//查找 age >=20 <=33的信息
db.workmate.find( {age: {$in: [20,33]}}, {name:true, age:true, "skill.skillOne": true, _id:false} );
//$nin修饰符 <a >b a<b
db.workmate.find( {age: {$nin: [20,33]}}, {name:true, age:true, "skill.skillOne": true, _id:false} );
$or修饰符
用来查询多个键值的情况,就比如查询同事中大于30岁或者会做PHP的信息,主要区别是两个Key值。$in修饰符是一个Key值.
//$or修饰符
//查询多个键值的情况 表示
db.workmate.find(
{$or: [
{age: {$gt: 20}},
{"skill.skillThree":"PHP"}
]},
{name:true, age:true, "skill.skillThree": true, _id:false}
);
$and修饰符
用来查找几个key值都满足的情况,比如要查询同事中大于30岁并且会做PHP的信息,这时需要注意的是这两项必须全部满足。
//$and修饰符
//$and用来查找几个key值都满足的情况
db.workmate.find(
{$and: [
{age: {$gt: 30}},
{"skill.skillThree":"PHP"}
]},
{name:true, age:true, "skill.skillThree": true, _id:false}
);
$not修饰符
用来查询除条件之外的值,比如我们现在要查找除年龄大于20岁,小于30岁的人员信息。
//$not修饰符
//用来查询除条件之外的值
//比如我们现在要查找除年龄大于20岁,小于30岁的人员信息
db.workmate.find(
{age: {$not: {$lte:30, $gte:20}}},
{name:true, age:true, "skill.skillOne": true, _id:false}
);
find的数组查询
当知道了一个人的爱好是’画画’,’聚会’,’看电影’,但我们不知道是谁,这时候我们就可以使用最简单的数组查询
注意查询多匹配的话要去掉[]
//查找一个人的爱好只有对应项目的人员信息 不常用
db.workmate.find(
{interest:['画画', '聚会', '看电影']},
{name:1, interest:1, age:1, _id:0}
);
db.workmate.find(
{interest:['写代码', '篮球']},
{name:1, interest:1, age:1, _id:0}
);
//带 '[]' 查找一个人的爱好只有'看电影'
db.workmate.find(
{interest:['看电影']},
{name:1, interest:1, age:1, _id:0}
);
//不带 '[]' 查找有‘看电影’爱好的人的信息
db.workmate.find(
{interest:'看电影'},
{name:1, interest:1, age:1, _id:0}
);
$all-数组多项查询
现在我们的条件升级了,要查询出喜欢看电影和看书的人员信息,也就是对数组中的对象进行查询,这时候要用到一个新的查询修饰符$all。
//$all-数组多项查询
//要查询出喜欢看电影和看书的人员信息
db.workmate.find(
{interest:{$all: ['写代码', '篮球']}},
{name:1, interest:1, age:1, _id:0}
);
这时候找到了兴趣中既有看电影又有看书的人员。
$in-数组的或者查询
主要满足数组中的一项就可以被查出来
比如现在要查询爱好中有看电影的或者看书的员工信息。
db.workmate.find(
{interest:{$in:["看电影","看书"]}},
{name:1,interest:1,age:1,_id:0}
)
$all-数组多项查询
要查询出喜欢看电影和看书的人员信息
db.workmate.find(
{interest:{$all: ['写代码', '篮球']}},
{name:1, interest:1, age:1, _id:0}
);
$size-数组个数查询
查找兴趣个数是五个的信息
db.workmate.find(
{interest:{$size: 5}},
{name:1, interest:1, age:1, _id:0}
);
$slice-显示选项
有时候我并不需要显示出数组中的所有值,而是只显示前两项
db.workmate.find(
{},
{name:1, interest: {$slice:2}, age:1, _id:0}
);
我们想显示兴趣的最后一项,可以直接使用slice:-1,来进行查询。
db.workmate.find(
{},
{name:1, interest: {$slice:-1}, age:1, _id:0}
);
find的参数使用方法
find还有几个常用的参数,这些参数多用在分页和排序上。
作一个最简单的分页,
我们把同事集合(collections)进行分页,
每页显示两个,
并且按照年龄从小到大的顺序排列
find参数:
query:这个就是查询条件,MongoDB默认的第一个参数。
fields:(返回内容)查询出来后显示的结果样式,可以用true和false控制是否显示。
limit:返回的数量,后边跟数字,控制每次查询返回的结果数量。
skip:跳过多少个显示,和limit结合可以实现分页。
sort:排序方式,从小到大排序使用1,从大到小排序使用-1。
db.workmate.find(
{},
{name:1, age:1, _id:0}
).limit(0).skip(2).sort({age:1});
$where修饰符
是一个非常强大的修饰符,但强大的背后也意味着有风险存在。
它可以让我们在条件里使用javascript的方法来进行复杂查询。
db.workmate.find(
{$where:"this.age>25"},
{name:1, age:1, _id:0}
).limit(0).skip(2).sort({age:1});
find如何在js文本中使用
hasNext循环结果
想在文本中执行我们的find语句要用到游标和循环的操作,先看一下代码,代码中我已经对每一句进行了注释。
var db = connect("company") //进行链接对应的集合collections
var result = db.workmate.find() //声明变量result,并把查询结果赋值给result
//利用游标的hasNext()进行循环输出结果。
while(result.hasNext()){
printjson(result.next()) //用json格式打印结果
}
forEach循环
利用hasNext循环结果,需要借助while的帮助,MongoDB也为我们提供了forEach循环,现在修改上边的代码,使用forEach循环来输出结果。
var db = connect("company") //进行链接对应的集合collections
var result = db.workmate.find() //声明变量result,并把查询结果赋值给result
//利用游标的hasNext()进行循环输出结果。
result.forEach(function(result){
printjson(result)
})
索引:构造百万级数据
索引的性能提现必须要有大量数据才能看出来,你说你有10条20条数据,这是根本看不出来效果的,这节课就通过随机数的方法,创造出一个百万级数据的数据库出来
制作随机数方法:
制作随机用户名:
//生成随机数
function getRandomNum(min, max) {
var range = max - min; //得到随机数区间
var rand = Math.random(); //得到随机值
return (min + Math.round(rand * range));
}
function getRandomUserName(min, max) {
//构造生成时的字母库数组
var tempStringArray = "123456789qwertyuiopasdfghjklzxcvbnm".split("");
var outPuttext = ""; //最后输出的变量
for (var i = 1; i<getRandomNum(min, max); i++){
outPuttext = outPuttext + tempStringArray[getRandomNum(0, tempStringArray.length)];
}
return outPuttext;
}
插入200万数据 这个过程可能2-3分钟,插入完成后,我们可以使用 db.randomInfo.stats() 这个命令查看数据中的数据条数。
var db = connect("company") //进行链接对应的集合collections
db.randomInfo.drop();
var tmpInfo = [];
var startTime = new Date().getTime();
for(var i = 0; i<2000000; i++){
tmpInfo.push({
userName:getRandomUserName(7, 16),
regeditTime:new Date(),
randNum0: getRandomNum(100000, 999999),
randNum1: getRandomNum(100000, 999999),
randNum2: getRandomNum(100000, 999999),
randNum3: getRandomNum(100000, 999999),
randNum4: getRandomNum(100000, 999999),
randNum5: getRandomNum(100000, 999999),
randNum6: getRandomNum(100000, 999999),
randNum7: getRandomNum(100000, 999999),
randNum8: getRandomNum(100000, 999999),
randNum9: getRandomNum(100000, 999999),
});
}
db.randomInfo.insert(tmpInfo);
var endTime = new Date().getTime();
var useTime = endTime - startTime;
print("[demo]: ----- [startTime] " + startTime + 'ms')
print("[demo]: ----- [endTime] " + endTime + 'ms')
print("[demo]: ----- [useTime] " + useTime + 'ms')
我们先制作一个普通查询,随便查找一个用户名,并计算出查询和打印的时间,因为有200万条数据,所以性能不会很高。
var startTime = new Date().getTime();
var db = connect("company") //进行链接对应的集合collections
var rs = db.randomInfo.find({userName: 'z3y4n5wjv', randNum0: 112042,});
rs.forEach(function(rs){
printjson(rs)
});
var endTime = new Date().getTime();
var useTime = endTime - startTime;
print("[demo]: ----- [startTime] " + startTime + 'ms')
print("[demo]: ----- [endTime] " + endTime + 'ms')
print("[demo]: ----- [useTime] " + useTime + 'ms')
上边的代码就是一个普通的查询,只不过是记录了时间。在终端运行后,可以得到大概的运行时间是0.8秒左右(电脑性能不同,有所不同),第一次无缓存的运行时间大概是3.5秒左右。这个时间是没办法满足我们的日常查询的。
建立索引
试着为用户名(username)建立索引。建立索引只需要一句话就可以了。
//将userName添加到索引
db.randomInfo.ensureIndex({userName:1})
//将randNum0添加到索引
db.randomInfo.ensureIndex({randNum0:1})
//删除username_1索引
db.randomInfo.dropIndex('username_1')
//查看现有索引
db.randomInfo.getIndexes()
这时候查询的时间缩短到了4ms左右,查询性能提升了大概200倍左右。
复合索引
索引中的小坑
记得我刚学MongoDB时,学会了索引,我就到处想用,甚至几百条数据的集合(collections),我也自作聪明的用一下,但结果往往是画蛇添足,走了不少弯路。通过实际开发和性能对比,我自己总结了几条不用索引的情况(不一定对,但是自己的经验之谈)。
- 数据不超万条时,不需要使用索引。性能的提升并不明显,而大大增加了内存和硬盘的消耗。
- 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表。
- 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明确的选择。
- 把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。
复合索引就是两条以上的索引
上边已经把username字段建立了索引,我们现在把randNum0,这个字段也设置成索引。
db.randomInfo.ensureIndex({randNum0:1})
建立好后,我们再用查询索引状态命令进行查询。
db.randomInfo.getIndexes()
两个索引同时查询
从性能上看并没有什么特殊的变化,查询时间还是在4ms左右
db.randomInfo.find({username:'7xwb8y3',randNum0:565509});
指定索引查询(hint)
数字的索引要比字符串的索引快,这就需要一个方法来打破索引表的查询顺序,用我们自己指定的索引优先查询,这个方法就是hint().
var rs= db.randomInfo.find({username:'7xwb8y3',randNum0:565509}).hint({randNum0:1});
删除索引
当索引性能不佳或起不到作用时,我们需要删除索引,删除索引的命令是dropIndex().
注意的是删除时填写的值,并不是我们的字段名称(key),而是我们索引查询表中的name值
db.randomInfo.dropIndex('randNum0_1');//索引的唯一ID
索引:全文索引
有些时候需要在大篇幅的文章中搜索关键词,比如我写的文章每篇都在万字以上,这时候你想搜索关键字是非常不容易的,MongoDB为我们提供了全文索引。
- 我们先建立一个集合(collections)-info
db.info.insert({contextInfo:"I am a programmer, I love life, love family. Every day after work, I write a diary."})
db.info.insert({contextInfo:"I am a programmer, I love PlayGame, love drink. Every day after work, I playGame and drink."}
建立全文索引
db.info.ensureIndex({contextInfo:'text'})
全文索引查找
建立好了全文索引就可以查找了,查找时需要两个关键修饰符:
- $text:表示要在全文索引中查东西。
- $search:后边跟查找的内容。
db.info.find({$text:{$search:"programmer"}})
查找多个词
db.info.find({$text:{$search:"programmer family diary drink"}})
如果我们这时候希望不查找出来有drink这个单词的记录,我们可以使用“-”减号来取消。
db .info.find({$text:{$search:"programmer family diary -drink"}})
转义符:
全文搜索中是支持转义符的,比如我们想搜索的是两个词(love PlayGame和drink),这时候需要使用\斜杠来转意。
db.info.find({$text:{$search:"\"love PlayGame\" drink"}})
管理:用户的创建、删除与修改
首先要进入我们的admin库中,进入方法是直接使用use admin 就可以。进入后可以使用show collections来查看数据库中的集合。默认是只有一个集合的(system.version)。
创建用户可以用db.createUser方法来完成,里边参数还是蛮多的,代码我写在下边,然后对每一项做出了解释。
//进入我们的admin库
use admin;
//创建用户
/*单独配置一个数据库的权限
内置角色:
数据库用户角色:read、readWrite;
数据库管理角色:dbAdmin、dbOwner、userAdmin;
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManage;
备份恢复角色:backup、restore;
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
超级用户角色:root
内部角色:__system
* */
db.createUser({
user: "zhangsan",
pwd: "123456",
customData: {
name : 'zhangsan',
email : 'abc@163.com',
age: 18
},
roles:[{
role: 'readWrite',
db: 'company'
},
'read'
],
})
查找用户信息
直接可以使用查找的方法,查找用户信息。
// 查找用户信息
db.system.users.find()
删除用户:
删除用户也是非常简单,直接用remove就可以删除这个用户的信息和权限。
db.system.users.remove({user:'zhangsan}')
建权
有时候我们要验证用户的用户名密码是否正确,就需要用到MongoDB提供的健全操作。也算是一种登录操作,不过MongoDB把这叫做建权。
如果正确返回1,如果错误返回0。
db.auth('zhangsan', '123456')
启动建权
重启MongoDB服务器,然后设置必须使用建权登录。
mongod --auth
登录
如果在配置用户之后,用户想登录,可以使用mongo的形式,不过需要配置用户名密码,我们就可以用给我们的权限对数据库操作了
mongo -u zhangsan -p 123456 127.0.0.1:27017/admin
管理:备份和还原
作为一个数据库管理员,对数据库的备份和还原是比作的两项工作。其实用起来是相当简单的,就是mongodump
和mongorestore
两个命令。
备份
比如现在我们备份所有MongoDB里的库的databack文件夹下,就可以把命令写成这样
mongodump --host 127.0.0.1 --port 27017 --out D:/databack/
数据恢复
备份好后,如果数据库有意外或者遭受到了攻击,我们要进行回复数据库,这时候就可以使用mongorestore
命令。
mongorestore --host 127.0.0.1 --port 27017 D:/databack/
网友评论