MongoDB学习笔记

#region 第一讲
Windows 下载安装
 1.下载地址: http://www.mongodb.org/downloads
 2.安装注意,在安装之前,在硬盘上建立一个目录存放 MongoDB 安装文件
 3.添加 MongoDBDATA,用于保存数据
 4.执行CMD命令
  4.1 bin\mongod.exe --dbpath MongoDBDATA
  4.2 作为 windows服务
   bin\mongod.exe --dbpath "\"MongoDBDATA"\" --install
 5.设置环境变量
  path中添加 ;MongoDB\bin
 6.启动数据库服务
  根据自己需要修改 mongodb.bat 文件
  mongod --dbpath MongoDBDATA
 7.启动数据库服务的配置文件
  http://www.uspcat.com/forum.php?mod=viewthread&tid=7722&extra=page%3D1
Shell基本操作
 启动 shell
 mongo 127.0.0.1:27017
 1.创建一个数据库
  use [dbName]
  如果什么都不干的话,数据库文件是不会建立的  
 2.查看所有数据库
  show dbs
 3.给指定数据库添加集合并且添加记录
  db.[documentName].insert({...})
 4.查看数据库中的所有文档
  show collections
  db.[documentName].find()
  db.[documentName].findOne()
 5.查询制定文档的数据
 6.更新文档数据(默认是更新第一条记录)
  db.[documentName].update({查询器},{更新器})
  db.[documentName].update({name:""},{$set:{name:"extjs4.1"}})
  var p = db.[documentName].findOne()
  db.[documentName].update(p,{"name","value"})
 7.删除文档中的数据
  db.[documentName].remove({})
 8.删除库中的集合
  db.[documentName].drop()
 9.删除数据库
  db.dropDatabase()
 10.Shell的help
  db.help()
  db.getName()
  db.status()
  db.[documentName].help()
 11.mongoDB的API
  http://api.mongodb.org/js/2.1.1/index.html
 * 数据库和集合命名
  1.不能使用特殊字符
  2.应全部小写
  3.最多64个字节
  4.数据库名不能与现有系统保留库同名,如 admin,local及config
 * shell 可以用 eval
BSON扩充的数据类型
 BSON是JSON的扩展,他先新增了日期,浮点等JSON不支持的数据类型
 * MongoVUE
  破解方法:找到 "4FF78130",把里面的子项全部删除,删除之后就又可以用14天
  安装
#endregion 第一讲

#region 第二讲
Document 数据插入
 1.插入文档  
 2.批量插入文档
  不支持批量插入,可以通过高级语言或 for循环
 3.Save操作
  insert时,如果_id相同,则会报错
Document 数据删除
 1.删除集合中的所有数据
  db.[documentName].remove()
  集合本身和索引不会被删除
 2.根据条件删除
  db.[documentName].remove({})
 3.小技巧
  如果想清除一个数据量十分庞大的集合
  直接删除该集合并重新建立索引的办法比直接用remove的效率高得多
Document 数据更新
 1.强硬的文档替换式更新操作
  db.[documentName].update({查询器},{修改器})
  强硬的更新会用新的文档代替老的文档
  db.Tickets.update({Multiple:10},{"Content":"100}),更新之后,就只有 Content 了
 2.主键冲突的时候会报错并且停止更新操作
 3.insertOrUpdate操作
  目的:查询器查询出来的数据就更新,查不出来就执行插入操作
  做法:db.[documentName].update({查询器},{修改器})
 4.批量更新操作
  默认情况下,修改器只会修改第一条查询出来的记录
  批量: db.[documentName].update({查询器},{$set:{name:"33"}},false,true)
 5.修改器
  $set:{field:value,field1:value1,...} 如果存在则更新,不存在则添加
  $inc:{numberField:numberValue}
  $unset:{field:value}删除指定的字段,
  $push:{field:value} 如果操作的是数组则添加新值,如果指定的field不存在,则创建数组,如果filed不是数组,则报错
  $pushAll:{field:arry} 可以对数组类型批量添加新值
  $addToSet:{field:value} 目标数组存在相同的项则不操作,不存在则加进去
  $pop:{arryField:value} value=1 删除arryField中的最后一个数值,value=-1删除arryField中第一个数值
  $pull:{arryField:value} 从 arryField中删除指定的value
  $pullALL:{arryField:arry} 从 arryField中删除arry
  db.[documentName].update({"books.type":"js"},{$set:{"books.$.author":"USPCAT"}})
 6.$addToSet与$each结合完成批量数组更新
  db.[documentName].update({查询器}, {$addToSet:{books:{$seach:["JS","DB"]}}})

 7.内存分配与查询效率
  当document被创建的时候DB为其分配内存和预留内存,当修改操作不超过预留内存的时候则速度非常快,
  如果document超过了分配的内存时,就要分配新内存,这时候查询就会慢
 8.runCommand函数和findAndModify函数
  runCommand可以执行 mongoDB 中的特殊函数
  findAndModify就是特殊函数之一,它用于返回update或remove后的文档
  runCommand({findAndModify":"processes",
    query:{查询器},
    sort(排序),
    new:true,
    update:{更新器}
    remove:true
   }).value
  ps = db.runCommand({
    "findAndModify":"persons",
    "query":{"name":"text"},
    "update":{"$set":{"email":"1221"}},
    "new":true
   }).value
  
#endregion 第二讲

 

#region 第三讲
Find
 操作
 $lt  小于
 $lte 小于等于
 $gt 大于
 $gte 大于等于
 $ne  不等于
 $in 包含
 $nin 不包含
 $or 或 
 db.[documentName].find({条件},{指定列})
 db.persons.find({},{_id:0,name:1,country:1})
 db.persons.find({age:{$gte:27,$lte25}},{}) 
 db.persons.find({country:{$in:[",USA","China"]}},{_id:0,name:1,m:1})
 $or:[c:{$gt:85},{e:{$gt:90}}] 
 db.persons.find({sex:{$in:[null]}})
 
 6.正则查询
  db.persons.find({name:/li/i})
 7. $not的使用
  可以用到任何地方进行取反操作
  db.persons.find({name:{$not:/li/i}})
  $nin只能用在集合操作上
 8.数组查询 $all
  查询喜欢 JS 和 MONGODB 的信息
  db.persons.find({books:{$all:["JS","MONGODB"]}},{_id:0,name:1,country:1})
  查询第二本书是 JAVA 的信息
  db.persons.find({"books.1":"JAVA"},{_id:0,name:1,country:1})
 9.查询指定长度数组 $size 它不能参与比较
  查询出喜欢的书箱数量有4本的学生
  db.persons.find({books:{$size:4}}, {_id:0,name:1,country:1})
  查询出喜欢的书箱数量大于3本的学生
   1.增加字段size
    db.persons.update({}, {$set:{size:4}},false,true)
   2.改变书箱更新方式,每次增加书籍的时候size增加1
    db.persons.update({查询器}, {$push:{books:"ORACLE"},$inc:{size:1}})
   3.利用 $gt 查询
    db.persons.find({size:{$gt:3}})
 10.$slice 返回文档中指定数组的内部值
  1.查询出 jim 的第2~4本书
   db.persons.find({name:"jim"}, {books:{$slice:[1,3]}})
  2.查询出最后一本书
 11. $elemMatch
  db.persons.find({school:{$elemMatch:{school:"K",score:"A"}}})
 12. $where
  查询年龄大于22岁,喜欢看C++书,在K学校上过学,
  但是我们要尽量避免使用,
  db.persons.find({"$where":function(){
   var books = this.books;
   var school = this.school;
   if(this.age > 22){
    for(var i = 0; i< books.length; i++){
     if(books[i] == "C++"){
      if(school){
       for(var j = 0; j < school.length; j++){
        if(school[j].school == "K"){
         return true;
        }
       }
       break;
      }
     }
    }
   }
  }})
分页与排序
 1.查询 persons 前5条
  db.persons.find({}, {_id:0, name:1}).limit(5)
 2.查询第5到10条,使用 sikp()
  db.persons.find({}, {_id:0, name:1}).limit(5).skip(5)
 3.sort 按年龄排序 (1是升序, -1是倒序)
  db.persons.find({}, {_id:0, name:1}).sort({age:1});
  注意:MongoDB的key可以是不同类型的数据,排序有优先级
  最小值 > null > 数字 > 字符串 > 对象|文档 > 数组 > 二进制 > 对象ID > 布尔 > 日期 > 时间戳 > 正则 > 最大值
 4.三条数据 一页进行分页
  第一页-> db.persons.find({},{_id:0,name:1}).limit(3),skip(0);
  第二页-> db.persons.find({},{_id:0,name:1}).limit(3),skip(3);  
  第一页-> db.persons.find({},{_id:0,name:1}).limit(pageSize),skip(pageIndex * PageSize);
 5. skip有性能问题,一般情况下可以对数据进行另一种设计以实现分页
  _id  name  age  date
  每次查询操作的时候后台传值把最后一个文档的日期保存下来
  db.persons.find({date:{$gt:日期数值}}).limit(3)
游标和其他知识
 1.
 var persons = db.persons.find({name:"jim"})
 while(persons.hasNext()){
  obj = persons.next();
  print(obj.books.length)
 }
 2.游标几个销毁的条件
  1.客户端发来信息叫他销毁
  2.游标迭代完成
  3.默认游标超过10分钟没用
 3.查询快照
  快照后就会针对不变的集合进行游标操作了,看看使用方法
  db.persons.find({$query:{name:"jim"},$snapshot:true})
  高级查询选项
  $query
  $orderby
  $maxscan:integer 最多扫描的文档数
  $min: doc 查询开始
  $max: doc 查询结束
  $hint: doc 使用哪个索引
  $explain:boolean 统计
  $snapshot:boolean 一致快照
 4.为什么用查询快照
  如果不使用快照,游标读取到的数据可能是已经读取过的或跳过某些数据
#endregion 第三讲


#region 第四讲
索引详细
 1.创建简单索引
  var start = new Date();
  for(var i=0; i<200000; i++){
   db.books.insert({name:i, name:i+"book"})
  }
  var end = new Date();
  end - start
  
  var start = new Date();
  db.books.find({number:72981})
  var end = new Date();
  end - start
  
  //添加索引
  db.books.ensureIndex({number:1})
 2.索引使用需要注意
  1.创建索引时,1是升序,-1是倒序
  2.索引在提高查询性能的同时,会影响插入性能
  3.索引要注意先后顺序
  4.索引不是万能的,每个键建立索引不一定能提高性能
  5.在做排序工作的时候,如果是越大数据量也可以考虑加上索引用来提高排序的性能
 3.索引名称
  1.用 MongoDBVUE 查看索引名称
  2.创建索引同时指定索引的名字
   db.books.ensureIndex({name:-1},{name:"book_name_index})
 4.唯一索引
  1.db.books.ensureIndex({name:-1}, {unique:true})
 5.剔除重复的值, dropDups:true 时会自动删除重复的记录
  db.books.ensureIndex({name:-1}, {unique:true}, {dropDups:true} )
 6.查询时使用指定的索引
  db.books.find({name:"IX_book_1", number:1}).hint({name:-1})
 7. expain
  1.如何详细查看本次查询使用了哪个索引和查询数据的状态信息
  db.books.find({name:"12book"}).explain()
索引管理
 1.system.indexes
  db.system.indexes.find()
  db.system.namespaces.find()
 2.后台执行
  执行创建索引的过程会暂时锁住表的问题如何解决  background:true
  db.books.ensureIndex({number:1},{background:true})
 3.删除索引
  批量删除和精确删除
   db.runCommand({dropIndexes:"books",index:"IX_books_name"})
   db.runCommand({dropIndexes:"books",index:"*"})
空间索引
 准备数据 map.js
 添加2D索引 db.map.ensureIndex({"gis":"2d"}, {min:-1, max:201})
 1.查询出距离点(70,180)最近的3个点
  db.map.find({"gis":{$near:[70,180]}}, {gis:1, _id:0}).limit(3)
 2.查询以点 (50,50)和点(190,190) 为对角线的正方形中所有点
  db.map.find( {gis:{"$within":{$box:[[50,50],[190,190]]}}}, {_id:0:gis:1}  )
 3.(56,80)为圆心,50为半径
  db.map.find( {gis:{$widthin:{$center:[[56,80],50]}}}, {_id:0,gis:1} )
#endregion 第四讲

#region 第五讲
count+distinct+group
 1.count 查询美国学生的人数
  db.persons.find({country:"USA"}).count()
 2.distinct 查询一共有多少个国家,分别是什么
  db.runCommand({distinct:"persons", key:"country"}).values
 3.group
  db.runCommand({group:{
   ns:集合名称,
   key:分组的键对象,
   initial:初始化累加器,
   $reduce:组分解器,
   condition:条件,
   finalize:组完成器
   
  }})
  1.查出 每个国家数学成绩最好的学生(成绩在90以上)
  db.runCommand({group:{
   ns:"persons",
   key:{"country":true},
   initial:{m:0},
   $reduce:function(doc,prev){
    if(doc.m > prev.m){
     prev.m = doc.m;
     prev.name = doc.name;
     prev.country = doc.country;
    }
   },
   condition:{m:{$gt:90}}
  
  }})
  2.在1的基础上,把每个人的信息连接起来放到 m 上
  db.runCommand({group:{
   ns:"persons",
   key:{"country":true},
   initial:{m:0},
   $reduce:function(doc,prev){
    if(doc.m > prev.m){
     prev.m = doc.m;
     prev.name = doc.name;
     prev.country = doc.country;
    }
   },   
   condition:{m:{$gt:90}},
   //完成器
   finalize:function(prev){
    prev.m = prev.name + " Math scores " + prev.m
   } 
  }})
 4.用函数格式化已经分组的键
  db.persons.insert({counTry:"China", m:91,c:80,name:"wuwuwu"})
  1.如果集合中出现键 count 和 counTry 同时存在,如何解决呢
  $key:function(doc){
   if(doc.counTry)return {country:doc.counTry}
   else{
    return {country:doc.country}
   }
   
  },
  
  db.runCommand({group:{
   ns:"persons",
   key:{"country":true},
   initial:{m:0},
   $key:function(doc){
    return {country : (doc.country ? doc.country : doc.counTry)}
   },
   $reduce:function(doc,prev){
    if(doc.m > prev.m){
     prev.m = doc.m;
     prev.name = doc.name;
     prev.country = doc.country?doc.country : doc.counTry     
    }
   },   
   condition:{m:{$gt:90}},
   //完成器
   finalize:function(prev){
    prev.m = prev.name + " Math scores " + prev.m
   } 
  }})
 
数据库命令操作
 1.命令执行器 runCommand
  用命令执行完成一次删除表的操作
  db.runcommand({drop:"map"})
 2.如何查询mongodb提供了哪些命令
  1.在 shell中执行 db.listCommands()
  2.访问网址: http://localhost:28017/_commands
 3.常用命令
  1.查询服务器版本和主机操作系统
   db.runCommand({buildInfo:1})
  2.查询执行集合的详细信息,大小,空间,索引等
   db.runCommand({collStats:"persons"})
  3.查看操作本集合最后一次错误信息
   db.runCommand({getLastError:"persons"})
固定集合特性
 1.特性
  1.固定集合默认是没有索引的,就算是 _id 也没有索引
  2.由于不需要分配新的空间,插入速度也是非常快的
  3.固定集合的顺序是确定的,导致查询速度也是非常快
  4.最适合的应用就是日志管理
 2.创建固定集合
  1.创建一个新的固定集合,大小为100字节,可以存储文档10个
   db.createCollection("mycoll", {size:100, capped:true, max:10})
  2.把一个普通的集合变成固定集合
   db.runCommand({convertToCapped:"persons", size:100000})
 3.反向排序,默认是插入顺序排序
  db.mycoll.find().sort({$natural:-1})
 4.尾部游标, shell 不支持, java和 php等驱动支持
  只能用到固定集合上面,没有结果的时候,不会自动销毁,它会一直等待结果的到来
GridFS文件系统
 1.概念 GridFS 是 MongoDB 自带的文件系统是二进制
  大型文件系统的绝大多数用GridFS
 2.利用工具
  mongofiles.exe
 3.使用 GridFS
  1.查看 GridFS 的所有功能
   cmd->mongofiles
  2.上传一个文件
   mongofiles -d foobar -l "E:\a.txt" put "a.txt"
  3.用 mongoVUE查看,在 shell 中无法查看
   mongofiles -d foobar get "a.txt"
  3.查看所有文件
   mongofiles -d foobar list
  4.删除已经存在的文件
   mongofiles -d foobar delete ‘a.txt‘
补充->服务器端脚本
 1.服务器端运行eval
  db.eval("function(name){return name}", "wujialong")
 2.在服务器上保存js变量,共全局调用
  1.把变量加载到 system.js 中
   db.system.js.insert({_id:"name",value:"wujialong"})
   db.system.js.insert({_id:"showName",value:function(){return name}})
  2.调用
   db.eval
  
#endregion 第五讲
  
  
#region 第六讲
mongoDB启动配置
 1.启动项 mongod -help
  --dbpath 默认是 c:\data\db
  --port 默认是 27017
  --fork
  --config 指定配置文件的路径
  --auth 用安全认证的方式启动数据库,默认不启用
  
  mongod.exe --config mongodb.conf
 2.停止服务
  1. ctrl+c
  2.use admin
  db.shutdownServer()
导出/导入,运行时备份
 导出
  -host 哪台机器
  -port 哪个端口
  -d 数据库
  -c 集合
  -o 文件名 
  CMD命令, mongoexport -d foobar -c persons -o c:\persons.js
 导入
  -db 数据库  
  mongoimport -db foobar -collection persons -file c:\persons.js
 
 
 备份
  1.运行时备份 mongodump
   API http:cn.docs.mongodb.org/manual/reference/mongodump
   mongodump -host 127.0.0.1:27017 -d foobar -o d:/foobar
  2.运行时恢复 mongorestore
   API http:cn.docs.mongodb.org/manual/reference/mongorestore
   mongorestore -host 127.0.0.1:27017 -d foobar -directoryperdb d:/foobar/foobar
  3.直接复制文件
   
fsync锁,数据修复
 上锁可以让缓冲池的数据全部保存到数据库,这在数据库备份的时候很有用
 上锁: db.runCommand({fsync:1,lock:1})
 解锁: db.currentOp()
 数据修复:当停电等不可逆转灾难时,由于 mongodb 的存储结构导致会产生垃圾数据,在数据恢复以后这些垃圾数据依然存在,这时数据库提供一个自我修复的能力,使用起来很简单
  db.repairDatabase()
用户管理,安全认证
 1.添加用户
  //添加用户
  use admin
  db.addUser("wujialong", "123")
  use foobar
  db.addUser("wujialongcn", "123")
  //切换登录用户
  db.auth("wujialong", "123")
  //删除用户
  db.sytem.users.remove({user:"wujialong"})
#endregion 第六讲

#region 第七讲
主从复制
 1.
  --master 设置为主数据库
  --slave 设置为从数据库
  --source 设置谁是主数据库
  --only 从节点 指定复制某个数据库,默认是复制全部数据库
  --slavedelay 从节点 设置主数据库同步数据的延迟时间(单位:秒)
  --fastsync 从节点以主数据库的节点快照为节点启动从数据库
  --autoresync 从节点数据与主数据库不同步,则重新同步数据库. 如:从数据库下线20天,当从节点重新上线后,会自动同步这20天的数据到从节点
  --oplogsize 主节点上 oplog的大小,越大的话,当从节点下线一段时间后重新上线时可以同步的数据越多
  
  在启动的时候,可以只有1个主数据库,0个从数据库.从数据库可以在运行时动态添加
 
 2.
  主数据库config内容
   dbpath = C:\master_slave\8888 #主数据库地址
   port = 8888 #主数据库端口号
   bing_ip = 127.0.0.1 #主数据库所在服务器
   master = true #设置为主数据库
  从数据库config内容
   dbpath = C:\master_slave\7777 #从数据库地址
   port = 7777
   bind_ip = 127.0.0.1 #从数据库所在服务器
   source = 127.0.0.1:8888 #主数据库地址
   slave = true #设置为从数据库
 3.利用 shell 动态添加和删除从节点
  在从节点中有 db.sources, 保存的是主节点信息,在配置的时候不设置 --source 参数,可以在shell中通过insert来动态配置
  db.sources.insert({"host":"127.0.0.1:8888"})  
  db.sources.remove({"host":"127.0.0.1:8888"})
副本集
 警告:
  1.只能在主节点上进行查询.
  2.备份节点不能进行查询操作.
 
 可以打开shell,查看提示信息的方式确定哪个是主节点
 1.设置
 A.
  dbpath = C:\replset\A
  port = 1111
  bing_ip = 127.0.0.1
  replSet = child/127.0.0.1:2222 #设置下一个同伴
 B. 
  dbpath = C:\replset\B
  port = 2222
  bing_ip = 127.0.0.1
  replSet = child/127.0.0.1:3333 #设置下一个同伴
 C.
  dbpath = C:\replset\C
  port = 3333
  bing_ip = 127.0.0.1
  replSet = child/127.0.0.1:1111 #设置下一个同伴
 2.连接副本集中任意一个,执行初始化操作
  use admin
  db.runCommand({"replSetInitiate":{
   "_id":"child",
   "members":[
    { "_id":1,
     "host":"127.0.0.1:1111"
    },
    { "_id":2,
     "host":"127.0.0.1:2222"
    },
    { "_id":3,
     "host":"127.0.0.1:3333"
    }
   ]
  }})
 3.查看副本集状态(只能在主节点中查询)
  rs.status()
 4.节点和初始高级参数
  standard 常规节点,可以参与投票,有可能成为活跃节点
  passive 副本节点,参与投票,但不会成为活跃节点
  arbiter 仲裁节点,只参与投票,不复制也不成为活跃节点
 5.高级级数
  priority 0~1000 之间, 0代表是副本节点, 1到1000是常规节点
  arbiterOnly:true 仲裁节点
  用法:
   "members":[
    { "_id":1,
     "host":"127.0.0.1:1111",
     arbiterOnly:true
    }
   ]
 6.优先级相同的时候,仲裁的规则
 7.读写分离操作(扩展读)
  一般情况下,副本节点是不能进行数据库读操作的
  但是在读取密集型的系统中进行读写分离是十分必要的
  设置: slaveOkey : true 主服务器进行写操作,从服务器进行读操作
  slaveOkey 在shell 中无法使用,在java等高级语言中有
 8. --master --oplogSize 字节
  在主数据库中设置同步日志保存的大小
  use local
  db.oplog.rs
#endregion 第七讲


#region 第八讲
分片 插入负载技术
 3.什么时候用到分片
  1.机器的磁盘空间不足
  2.单个服务器已经不能满足大量的插入操作
  3.想把大数据放到内存中提高性能
 4.分片步骤
  1.创建一个配置服务器
   config.conf:
    dbpath = config
    port = 2000
    bind_ip = 127.0.0.1   
   mongod --config config.conf
  2.创建路由服务器,并且连接配置服务器
   路由器调用 mongos 命令:
   mongos --port 1000 --configdb 127.0.0.1:2000
   
  3.添加两个分片数据库
   8081和8082
  4.利用路由为集群添加分片(允许本地访问)
   db.runCommand({addshard:"127.0.0.1:8081", allowLocal:true})
   db.runCommand({addshard:"127.0.0.1:8082", allowLocal:true})
   警告:在进行这些操作之前,不能使用任何数据库语句
  5.启用数据库分片,
   db.runCommand({"enablesharding" : "foobar"})
  6.对集合进行分片
   db.runCommand({ "shardcolleciton", "foobar.bar", "key":{"_id":1} })
  7.使用大数据量进行测试
  8.查看配置库于分片服务器的配置存储
   db.printShardingStatus()
  9.查看集群对bar的自动分片机制配置信息
   mongs> use config
   mongos> db.shards.find()
#endregion 第八讲
#endregion 第八讲

MongoDB学习笔记,布布扣,bubuko.com

MongoDB学习笔记

上一篇:atitit. java queue 队列体系and自定义基于数据库的队列总结o7t


下一篇:ubantu 下 修改mysql 默认编码