# 使用mongodb
在命令窗口输入mongo进入mongo语法
- show dbs
展示所有数据库
- db
查看当前数据库
- db.version()
查看数据库版本
- use xxx
使用选定的数据库,如果没有即为创建新的数据库
- show collections
显示数据库中的集合
- db.xxx.insert()
新建数据集合和插入文件(数据),当集合没有时,这时候就可以新建一个集合,并向里边插入数据。Demo:db.user.insert({"name":"apple"})
//批量插入
db.test.insert([
{"_id":1},
{"_id":2},
{"_id":3}
])
- db.xxx.find()
查询所有数据,这条命令会列出集合下的所有数据,可以看到MongoDB是自动给我们加入了索引值的。
- 没有加参数即为查找全部
- db.student.find({"score.shuxue":70});精确匹配
- db.student.find({"score.shuxue":70 , "age":12})多个条件
- db.student.find({"score.yuwen":{$gt:50}});大于条件
- db.student.find({$or:[{"age":9},{"age":11}]});或者。寻找所有年龄是9岁,或者11岁的学生
- db.restaurants.find().sort( { "borough": 1, "address.zipcode": 1 } )打点调用sort,表示升降排序
- db.xxx.findOne()
查询第一个符合要求的文件数据eg:db.user.findOne({name:"apple",age:18})
- update
更新
- db.student.update({"name":"小明"},{$set:{"age":16}});查找第一个名字叫做小明的,把年龄更改为16岁 $set 更改局部
- db.student.update({"sex":"男"},{$set:{"age":33}},{multi: true});更改所有符合的,如果不加multi,只会默认修改第一条符合的数据
- db.student.update({"name":"小明"},{"name":"大明","age":16});完整替换,不出现$set关键字了:
- db.workmate.update({"name":"MinJie"},{$unset:{"age":''}}); $unset 用于将key删除
- db.workmate.update({"name":"MinJie"},{$inc:{"age":-2}});它是对value值的修改,但是修改的必须是数字,字符串是不起效果的。我们现在要对MiJie的年龄减去2岁,就可以直接用 $inc 来操作。
- db.workmate.update({name:'xiaoWang'},{$set:{age:20}},{upsert:true}); upsert 是在找不到值的情况下,直接插入这条数据。true代表没有就添加,false代表没有不添加(默认值)。
- update数组修改器
//$push:给小王加上一个爱好(interset)为draw,interest就是个数组
db.workmate.update({name:'xiaoWang'},{$push:{interest:'draw'}})
//$ne:检查一个值是否存在,如果不存在再执行操作,存在就不执行
//如果xiaoWang的爱好(interest)里没有palyGame这个值,我们就加入Game这个爱好
db.workmate.update({name:'xiaoWang',"interest":{$ne:'playGame'}},{$push:{interest:'Game'}})
//$addToSet 升级版的$ne
//小王(xiaoWang)兴趣(interest)中有没有阅读(readBook)这项,没有则加入读书(readBook)的兴趣.
db.workmate.update({name:"xiaoWang"},{$addToSet:{interest:"readBook"}})
//$each 批量追加 它可以传入一个数组,一次增加多个值进去,相当于批量操作,性能同样比循环操作要好很多
//一次加入三个爱好,唱歌(Sing),跳舞(Dance),编码(Code)
var newInterset=["Sing","Dance","Code"];
db.workmate.update({name:"xiaoWang"},{$addToSet:{interest:{$each:newInterset}}})
//$pop 删除数组值$pop只删除一次,并不是删除所有数组中的值。而且它有两个选项,一个是1和-1。
//1:从数组末端进行删除 -1:从数组开端进行删除
db.workmate.update({name:'xiaoWang'},{$pop:{interest:1}})
//定位修改
//只知道修改数组的第几位,但并不知道是什么,这时候我们可以使用interest.int 的形式
//修改xiaoWang的第三个兴趣
db.workmate.update({name:'xiaoWang'},{$set:{"interest.2":"马克杯"}})
- remove
删除文件数据,注意的是要跟一个条件。Demo:db.user.remove({name:"jspang"})使用justone选项将删除操作仅限于一个匹配的文档。db.restaurants.remove( { "borough": "Queens" }, { justOne: true } )
- drop
db.xxx.drop(),删除整个集合,慎用!
- dropDatabase()
删除整个数据库!!!
- mongoimport --db test --collection restaurants --drop --file primer-dataset.json
数据导入数据库
- -db test 想往哪个数据库里面导入
- --collection restaurants 想往哪个集合中导入
- --drop 把集合清空
- --file primer-dataset.json 哪个文件
- delete
remove() 方法已经过时了,现在官方推荐使用 deleteOne() 和 deleteMany() 方法。
//删除集合下全部文档:
db.inventory.deleteMany({})
//删除 status 等于 A 的全部文档:
db.inventory.deleteMany({ status : "A" })
//删除 status 等于 D 的一个文档:
db.inventory.deleteOne( { status: "D" } )
# 写入数据和性能问题
如果在循环插入和批量插入举起不定,那就选批量插入吧,它会给我们更优的性能体验
// var startTime = (new Date()).getTime(); //得到开始时间
// var db = connect('log'); //链接数据库
// //开始循环
// for(let i=0;i<1000;i++){
// db.test.insert({num:i});
// }
//
// var runTime = (new Date()).getTime()-startTime;//计算时间差
// print ('This run this is:'+runTime+'ms');//打印出来
//700ms
var startTime = (new Date()).getTime();
var db = connect('log');
var tempArray = [] //声明一个数组
for(let i=1001;i<2000;i++){ //循环向数组中放入值
tempArray.push({num:i});
}
db.test.insert(tempArray) //批量一次插入
var runTime = (new Date()).getTime()-startTime;
print ('This run this is:'+runTime+'ms');
//30ms
# 状态返回与安全
db.runCommand():
db.workmate.update({sex:1},{$set:{money:1000}},false,true)
var resultMessage=db.runCommand({getLastError:1})
printjson(resultMessage);
{
"connectionId" : 1,
"updatedExisting" : true,
"n" : 2,
"syncMillis" : 0,
"writtenTo" : null,
"err" : null,
"ok" : 1
}
//ok==1即为成功
findAndModify
var myModify={
findAndModify:"workmate",
query:{name:'JSPang'},
update:{$set:{age:18}},
new:true //更新完成,需要查看结果,如果为false不进行查看结果
}
var ResultMessage=db.runCommand(myModify);
printjson(ResultMessage)
{
"lastErrorObject" : {
"n" : 1,
"updatedExisting" : true
},
"value" : {
"_id" : ObjectId("5d3ffa8a9ed934af890507d9"),
"name" : "JSPang",
"age" : 18,
"sex" : 1,
"job" : "前端",
"skill" : {
"skillOne" : "HTML+CSS",
"SkillTwo" : "JavaScript",
"SkillThree" : "PHP"
},
"regeditTime" : ISODate("2019-07-30T08:06:34.505Z"),
"money" : 1000
},
"ok" : 1
}
# findAndModify属性值
query:需要查询的条件/文档
sort: 进行排序
remove:[boolean]是否删除查找到的文档,值填写true,可以删除。
new:[boolean]返回更新前的文档还是更新后的文档。
fields:需要返回的字段
upsert:没有这个值是否增加。
# js文件写mongodb
var userName="jspang";
var jsonDdatabase={"loginUnser":userName}
var db = connect("apple");
db.login.insert(jsonDdatabase);
print("[demo]log print success");
//mongo xx.js
# find不等修饰符
- 筛选字段
db.workmate.find(
{"skill.skillOne":"HTML+CSS"},
{name:true,"skill.skillOne":true}
)
//默认会显示_id的,如果不需要,可以设为false
- 修饰符
- 小于($lt):英文全称less-than
- 小于等于($lte):英文全称less-than-equal
- 大于($gt):英文全称greater-than
- 大于等于($gte):英文全称greater-than-equal
- 不等于($ne):英文全称not-equal
//公司内年龄小于30大于25岁的人员。看下面的代码。
db.workmate.find(
{age:{$lte:30,$gte:25}},
{name:true,age:true,"skill.skillOne":true,_id:false}
)
# find多条件查询
//$in相对的修饰符是$nin
db.workmate.find({age:{$in:[25,33]}},
{name:1,"skill.skillOne":1,age:1,_id:0}
)
//查询同事中大于30岁或者会做PHP的信息
db.workmate.find({$or:[
{age:{$gte:30}},
{"skill.skillThree":'PHP'}
]},
{name:1,"skill.skillThree":1,age:1,_id:0}
)
//查询同事中大于30岁并且会做PHP的信息
db.workmate.find({$and:[
{age:{$gte:30}},
{"skill.skillThree":'PHP'}
]},
{name:1,"skill.skillThree":1,age:1,_id:0}
)
//注意$not修饰符不能应用在条件语句中,只能在外边进行查询使用。
db.workmate.find({
age:{
$not:{
$lte:30,
$gte:20
}
}
},
{name:1,"skill.skillOne":1,age:1,_id:0}
)
# find基本数组查询
//加上中括号就相当于完全匹配了
db.workmate.find({interest:['画画','聚会','看电影']},
{name:1,interest:1,age:1,_id:0}
)V
//如果只想查数组里可能的一个值,不需要加中括号
db.workmate.find({$and:[{interest:'看电影'},{interest:'聚会'}]},
{name:1,interest:1,age:1,_id:0}
)
# $all
查询出喜欢看电影和看书的人员信息,也就是对数组中的对象进行查询,这时候要用到一个新的查询修饰符$all
db.workmate.find(
{interest:{$all:["看电影","看书"]}},
{name:1,interest:1,age:1,_id:0}
)
# $in
$in主要满足数组中的一项就可以被查出来
db.workmate.find(
{interest:{$in:["看电影","看书"]}},
{name:1,interest:1,age:1,_id:0}
)
# $size
$size修饰符可以根据数组的数量查询出结果。要查找兴趣的数量是5个人员信息,这时候就可以使用$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参数
- query:这个就是查询条件,MongoDB默认的第一个参数。
- fields:(返回内容)查询出来后显示的结果样式,可以用true和false控制是否显示。
- limit:返回的数量,后边跟数字,控制每次查询返回的结果数量。
- skip:跳过多少个显示,和limit结合可以实现分页。
- sort:排序方式,从小到大排序使用1,从大到小排序使用-1
db.workmate.find({},{name:true,age:true,_id:false}).limit(0).skip(2).sort({age:1});
# $where
//this指向的是workmate(查询集合)本身。这样可以在程序中随意调用。
//虽然强大灵活,但这种查询对于数据库的压力和安全性都会变重,所以尽量减少$where修饰符的使用。
db.workmate.find(
{$where:"this.age>30"},
{name:true,age:true,_id:false}
)
# 循环打印数据
var db = connect("company") //进行链接对应的集合collections
var result = db.workmate.find() //声明变量result,并把查询结果赋值给result
//利用游标的hasNext()进行循环输出结果。
while(result.hasNext()){
printjson(result.next()) //用json格式打印结果
}
---------------
var db = connect("company") //进行链接对应的集合collections
var result = db.workmate.find() //声明变量result,并把查询结果赋值给result
result.forEach(function(result){
printjson(result)
})
# 导入百万数据
//生成随机数
function GetRandomNum(min,max){
let range = max-min; //得到随机数区间
let rand = Math.random(); //得到随机值
return (min + Math.round(rand *range)); //最小值+随机数取整
}
//console.log(GetRandomNum(10000,99999));
//生成随机用户名
function GetRadomUserName(min,max){
let tempStringArray= "123456789qwertyuiopasdfghjklzxcvbnm".split("");//构造生成时的字母库数组
let outPuttext = ""; //最后输出的变量
//进行循环,随机生产用户名的长度,这里需要生成随机数方法的配合
for(let i=1 ;i<GetRandomNum(min,max);i++){
//随机抽取字母,拼装成需要的用户名
outPuttext=outPuttext+tempStringArray[GetRandomNum(0,tempStringArray.length)]
}
return outPuttext;
}
// console.log(GetRadomUserName(7,16))
// var startTime=(new Date()).getTime();
// var db = connect('company');
// db.randomInfo.drop();
var tempInfo = [];
for (let i=0;i<2000000;i++){
tempInfo.push({
username:GetRadomUserName(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),
randNum8:GetRandomNum(100000,999999),
})
}
db.randomInfo.insert(tempInfo);
# 普通查询
var startTime = new Date().getTime() //得到程序运行的开始时间
var rs=db.randomInfo.find({username:"tfruhjy8k"})
var runTime = new Date().getTime()-startTime; //得到程序运行时间
print('[SUCCESS]This run time is:'+runTime+'ms') //打印出运行时间
# 建立索引
无论是在关系型数据库还是文档数据库,建立索引都是非常重要的。索引这东西是要消耗硬盘和内存资源的,所以还是要根据程序需要进行建立了。MongoDB也进行了限制,只允许我们建立64个索引值。
试着为用户名(username)建立索引。建立索引只需要一句话就可以了。
db.randomInfo.ensureIndex({username:1})
查看现有索引
db.randomInfo.getIndexes()
总结
- 数据不超万条时,不需要使用索引。性能的提升并不明显,而大大增加了内存和硬盘的消耗。
- 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表。
- 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明确的选择。
- 把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。
# 复合索引
复合索引就是两条以上的索引
db.randomInfo.find({username:'7xwb8y3',randNum0:565509});
# 指定索引查询(hint)
数字的索引要比字符串的索引快,这就需要一个方法来打破索引表的查询顺序,用指定的索引优先查询,这个方法就是hint().
db.randomInfo.find({username:'7xwb8y3',randNum0:565509}).hint({randNum0:1});
# 删除索引
当索引性能不佳或起不到作用时,我们需要删除索引,删除索引的命令是dropIndex().
//新建
db.randomInfo.ensureIndex({randNum0:1})
//查看
db.randomInfo.getIndexes()
//删除
db.randomInfo.dropIndex('randNum0_1');//索引的唯一ID
{
"v" : 2,
"key" : {
"randNum0" : 1
},
"name" : "randNum0_1",
"ns" : "company.randomInfo"
}
注意
这里需要注意的是删除时填写的值,并不是我们的字段名称(key),而是我们索引查询表中的name值。
# 建立全文索引
db.info.ensureIndex({contextInfo:'text'})
需要注意的是这里使用text关键词来代表全文索引。
建立好了全文索引就可以查找了,查找时需要两个关键修饰符:
- $text:表示要在全文索引中查东西。
- $search:后边跟查找的内容。 db.info.find({$text:{$search:"programmer"}})
查找多个词
全文索引是支持多个次查找的,比如我们希望查找数据中有programmer,family,diary,drink的数据(这是或的关系),所以两条数据都会出现。
db.info.find({$text:{$search:"programmer family diary drink"}})
如果希望不查找出来有drink这个单词的记录,我们可以使用“-”减号来取消。
dbd .info.find({$text:{$search:"programmer family diary -drink"}})
转义符:
全文搜索中是支持转义符的,比如我们想搜索的是两个词(love PlayGame和drink),这时候需要使用\斜杠来转意。
db.info.find({$text:{$search:"\"love PlayGame\" drink"}})
# 数据备份
mongodump备份的基本格式
mongodump
--host 127.0.0.1
--port 27017
--out D:/databack/backup
--collection myCollections
--db test
--username username
--password password
//比如现在我们备份所有MongoDB里的库到D盘的databack文件夹下,就可以把命令写成这样
mongodump --host 127.0.0.1 --port 27017 --out D:/databack/
# 数据恢复
mongorestore
--host 127.0.0.1
--port 27017
--username username
--password password
<path to the backup>
mongorestore --host 127.0.0.1 --port 27017 D:/databack/
# node操作mongodb
需要引包
npm install mongodb
var express = require("express");
//数据库引用
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var app = express();
//数据库连接的地址,最后的斜杠表示数据库名字
var shujukuURL = 'mongodb://localhost:27017/itcast';
app.get("/",function(req,res){
res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
//连接数据库,这是一个异步的操作
MongoClient.connect(shujukuURL, function(err, db) {
if(err){
res.send("数据库连接失败");
return;
}
res.write("恭喜,数据库已经成功连接 \n");
db.collection("teacher").insertOne({"name":"哈哈"},function(err,result){
if(err){
res.send("数据库写入失败");
return;
}
res.write("恭喜,数据已经成功插入");
res.end();
//关闭数据库
db.close();
});
});
});
app.listen(3000);