MongoDB 学习笔记

以下命令中若有 --fork 参数(表示后台运行),则只在linux下有用,在windows下需去掉此参数

命令集:
use foobar  切换到foobar数据库
help 显示所有可用命令
db.help() 显示数据库级别的命令
db.foo.help() 显示集合级别的命令

db  显示当前数据库


db.blog.insert({"title":"My Blog"})

db.blog.update({"title":"My Blog"}, {"title":"My first blog"})
更新记录, 第一个参数是要更新记录的查询条件, 第二个参数是更新后的内容

db.blog.find({}, {"author" : 1, "email": 1})
   第一个参数为查询条件,第二个参数为要返回的字段列表。


修改器
$inc 增加指定的键的值,如不存在则创建。
   e.g.  db.blog.update({"title":"My Blog"}, {"$inc": {"vote" : 10}})

$set 更新指定的键的值,如不存在则创建。
   e.g.  db.blog.update({"title":"My Blog"}, {"$set": {"author" : "shj"}})

$unset 移除一个键。e.g. db.blog.update({"title":"My Blog"}, {"$unset": {"author" : 1}})

$push 向数组末尾加入一个元素,如不存在则创建数组。
    e.g. db.blog.update({"title":"My Blog"}, {"$push": {"comments": {"name":"joe", "comment" : "good"}}})

$addToSet 数组里面若不存在对应的值,就加进去。
    e.g. db.users.update({"name":"shj"}, {"$addToSet": {"emails" : "123@163.com"}})
    emails数组里如果没有123@163.com, 则会补添加进去。

$pop 从数组中删除一个元素。 只能删除头部或尾部元素。
    e.g. db.users.update({"name":"shj"},{"$pop": {"emails": 1}})
    其中1表示从数组末尾删除一个元素。-1 则是从头部删除一个。

$pull 从数组中删除一个元素。
    e.g. db.lists.update({}, {"$pull": {"todo":"laundry"}}) 删除todo数组中的"laundry"

save 保存一个文档。若存在则更新。
    e.g. db.blog.save({"title":"My Blog"})

findAndModify 找到并修改。这是一个原子操作。
db.runCommand({"findAndModify": "blog", // blog -- 集合名
               "query":{"votes":0},     // query -- 查询条件
               "sort":{"votes":-1},     // sore -- 排序条件
               "update":{"$set", {"votes": 2}},
               "new":true               // new -- 返回更新前的还是更新后的文档
               //,"remove" : ture       // remove -- 删除query匹配的文档
              })  // update -- 更新操作

查询条件
1. $lt, $lte, $gt, $gte
  db.users.find({"age":{"$gte": 18, "$lte" : 30}})

2. $in, $nin
  db.users.find({"userid" : {"$in" : [12345, "joe"]}})

3. $or
  db.users.find({"$or" : [{"userid" : 12345}, {"name" : "joe"}]})

4. $not
  db.users.find({"userid" : {"$not" : {"name" : "joe"}}})

5. null值,匹配自身和不存在该键的文档
   e.g. db.users.find({"birthday" : null}) 匹配birthday的值为null的文档和所有
   不存在birthday这个键的文档。可通过$exists 条件判断键是否存在。

6. $exists
   e.g. db.users.find({"birthday" : {"$in" : [null], "$exists" : true}})

7. $all 多个元素来匹配数组
   e.g. db.food.insert({"fruit" : ["apple", "banana", "peach"]})  
        db.food.insert({"fruit" : ["apple", "kumquat", "orange"]})
        db.food.insert({"fruit" : ["cherry", "banana", "apple"]})
        db.food.find({"fruit" : {$all : ["apple", "banana"]}}) -- 返回第1条和第3条

8. $size 查询指定长度的数组
   e.g. db.food.find({"fruit" : {$size : 3}})

9. $slice 返回数组的一个子集合
   e.g. db.blog.find({"title" : "my blog"}, {"comments" : {"$slice" : 10}}) -- 返回前10条comments
        db.blog.find({"title" : "my blog"}, {"comments" : {"$slice" : -10}}) -- 返回最后10条comments
        db.blog.find({"title" : "my blog"}, {"comments" : {"$slice" : [2, 10]}}) -- 忽略前面的2条,返回2条之后的10条comments

10. $elemMatch 将限定条件进行分组,仅当需要对一个内嵌文档的多个键操作时才会用到。
    e.g.  db.blog.insert({"title" : "my blog",
               "comments" : [
                            {"author" : "joe", "score" : 4, "comment": "nice"},
                            {"author" : "mary", "score" : 6, "comment": "terrible"}]})
    假设需要查找由joe发表的5分以上的评论,则:
    db.blog.find({"comments" : {"author" : "joe", "score" : {"$gte":5}}}) -- 不对,内嵌文档查询要求内嵌文档完全匹配
    db.blog.find({"comments.author" : "joe", "comments.score" : {"$gte":5}}) --不对,author和score是or的关系,不是要求的and
    db.blog.find({"comments" : {"$elemMatch": {"author" : "joe", "score" : {"$gte":5}}}}) -- 正确

11. $near 用于查询附近的坐标、位置
   e.g.  db.map.find({"gps" : {"$near" : [40, -73]})

12. $within 找到指定形状内的文档。
   e.g. db.map.find({"gps" : {"$within" : {"$box" : [[10, 20], [15,30]]}}})
   $box参数是两个元素的数组,第一个指定了左下角的坐标,第二个指定了右上角的坐标
   e.g. db.map.find({"gps" : {"$within" : {"$center" : [[10, 20], 5]}}})
   $center参数是两个元素的数组,第一个是圆心,第二个是半径
 
13. $where
   e.g. db.blog.find({"$where" : function(){
           for(var current in this){
          for(var other in this){
             if(current != other && this[current] == this[other]){
            return true;
         }
          }
       }
       return false;
        }})   
   返回true的文档将做为结果的一部分返回


db.blog.find().limit(3) -- 限制返回的结果数为3
db.blog.find().skip(3) -- 忽略前三个匹配文档
db.blog.find().sort({name: 1 , age : -1}) -- name升序,age降序

db.blog.ensureIndex({"username":1}, {"unique" : true}) -- 对username进行索引,并设置唯一
db.blog.find().explain("executionStats")


db.blog.count() -- 集合中的文档数量

db.blog.drop() -- 删除一个集合

db.listCommands() -- 列出所有命令

db.createCollection({"my_collection", {capped: true, size: 10000}}) -- 创建固定集合,大小10000字节

db.serverStatus() -- 查看实例运行状态
db.stats() -- 查看数据库状态信息


开启profiling(慢查询日志,用于记录执行时间较长的命令,以便于调优)
(1) 在启动时设置 mongod -profile=级别
(2) > db.setProfilingLevel(级别, slowms);
说明:级别有三种: 0(不开启),1(记录慢命令,默认为 > 100ms),2(记录所有命令)
开启后可以查询: >use admin
                >db.system.profile.find()


导出数据:
mongoexport -d my_mongodb -c user -o e:\user.dat
说明: -d 要导出的数据库名
       -c 要导出的数据库表
       -o 存放导出文件的位置
mongoexport -d my_mongodb -c user --type=csv -f uid,username,age -o e:\user_csv.dat
说明:导出CSV格式的文件,必须有 -f 参数,表示需要导出的列

导入数据:
mongoimport -d my_mongodb -c user e:\user.dat
mongoimport -d my_mongodb -c user --type csv --headerline --file e:\user_csv.dat
说明:--headerline 批明不导入第一行,因为第一行是列名


数据备份:
mongodump -d test  -o e:\my_mongodb_dump

数据恢复:
mongorestore -d test e:\my_mongodb_dump\test


访问控制
1. 绑定 IP 内网地址访问 MongoDB 服务
   mongod --bind_ip 192.168.1.103     只允许192.168.1.103 访问 MongoDB 服务
2. 设置监听端口
   mongod --bind_ip 192.168.1.103 --port 28018
3. 使用用户名和口令登录
   启动:mongod --auth
   要先添加用户后方可用用户名登陆:
    > use admin   #1. 切换数据库
    >db.createUser(  
      {
        user: "dba",
        pwd: "dba",
        roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
      }
    )   #2. 创建用户,只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
    > db.auth('dba','dba')  #3. 认证用户
    > use test    #4. 切换数据库
    > db.createUser(  #5. 创建一个连接数据库的帐号
        {
          user: "zjyr",
          pwd: "zjyr",
          roles: [
             { role: "read", db: "test" }    #只读帐号
          ]
        }
    )
   连接:mongo -u root -p


MapReduce:
准备的数据:
> db.students.insert({classid:1, age:14, name:'Tom'})
> db.students.insert({classid:1, age:12, name:'Jacky'})
> db.students.insert({classid:2, age:16, name:'Lily'})
> db.students.insert({classid:2, age:9, name:'Tony'})
> db.students.insert({classid:2, age:19, name:'Harry'})
> db.students.insert({classid:2, age:13, name:'Vincent'})
> db.students.insert({classid:1, age:14, name:'Bill'})
> db.students.insert({classid:2, age:17, name:'Bruce'})

设置Map函数:Map 函数必须调用 emit(key, value) 返回键值对,使用 this 访问当前待处理的 Document
> map = function() { emit(this.classid, 1) }
设置reduce函数
> reduce = function(key, values) {
    var x = 0;
    values.forEach(function(v) { x += v });
    return x;
  }
进行处理:
> res = db.runCommand({
    mapreduce:"students",
    map:map,
    reduce:reduce,
    out:"students_res"
  })
查看结果:
> db.students_res.find()

利用 finalize() 我们可以对 reduce() 的结果做进一步处理:
> f = function(key, value) { return {classid:key, count:value}; }
> res = db.runCommand({
    mapreduce:"students",
    map:map,
    reduce:reduce,
    out:"students_res",
    finalize:f
 })
 
 
 
 部署 Replica Sets
 1、 创建数据文件存储路径
[root@localhost ~]# mkdir -p /data/data/r0
[root@localhost ~]# mkdir -p /data/data/r1
[root@localhost ~]# mkdir -p /data/data/r2

2、 创建日志文件路径
[root@localhost ~]# mkdir -p /data/log

3、创建主从 key 文件,用于标识集群的私钥的完整路径,如果各个实例的 key file 内容不一
致,程序将不能正常用。
[root@localhost ~]# mkdir -p /data/key
[root@localhost ~]# echo "this is rs1 super secret key" > /data/key/r0
[root@localhost ~]# echo "this is rs1 super secret key" > /data/key/r1
[root@localhost ~]# echo "this is rs1 super secret key" > /data/key/r2
[root@localhost ~]# chmod 600 /data/key/r*

4、启动 3 个实例
[root@localhost ~]# /Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r0 --fork --port
     28010 --dbpath /data/data/r0 --logpath=/data/log/r0.log --logappend
[root@localhost ~]# /Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r1 --fork --port
     28011 --dbpath /data/data/r1 --logpath=/data/log/r1.log --logappend
[root@localhost ~]# /Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r2 --fork --port
     28012 --dbpath /data/data/r2 --logpath=/data/log/r2.log --logappend
    
5、配置及初始化 Replica Sets
[root@localhost bin]# /Apps/mongo/bin/mongo -port 28010
> config_rs1 = {_id: 'rs1', members: [
    {_id: 0, host: 'localhost:28010', priority:1}, --成员 IP 及端口, priority=1 指 PRIMARY
    {_id: 1, host: 'localhost:28011'},
    {_id: 2, host: 'localhost:28012'}]
    }
> rs.initiate(config_rs1); --初始化配置
> rs.status() -- 查看复制集状态
> rs.isMaster() -- 查看 Replica Sets 状态

6. 添加新的节点
  按照上述说的方法启动一个mongo,然后执行:
rs1:PRIMARY> rs.add("localhost:28013")

7. 删除节点
rs1:PRIMARY> rs.remove("localhost:28013")



Sharding 分片
要构建一个 MongoDB Sharding Cluster,需要三种角色:
(1) Shard Server
    即存储实际数据的分片,每个 Shard 可以是一个 mongod 实例,也可以是一组 mongod 实例构成的 Replica Set。
(2) Config Server
    为了将一个特定的 collection 存储在多个 shard 中,需要为该 collection 指定一个 shard key,
例如{age: 1} , shard key 可以决定该条记录属于哪个 chunk。 Config Servers 就是用来存储:
所有 shard 节点的配置信息、每个 chunk 的 shard key 范围、 chunk 在各 shard 的分布情况、
该集群中所有 DB 和 collection 的 sharding 配置信息。
(3) Route Process
    这是一个前端路由,客户端由此接入,然后询问 Config Servers 需要到哪个 Shard 上查询或
保存记录,再连接相应的 Shard 进行操作,最后将结果返回给客户端。

sharding cluster创建步骤:
(1) 启动shard server1
mongod --shardsvr --port 20000 --dbpath E:\MongoDB\Server\data\shard\s1 --logpath E:\MongoDB\Server\data\shard\log\s1.log --directoryperdb

(2) 启动shard server2
mongod --shardsvr --port 20001 --dbpath E:\MongoDB\Server\data\shard\s2 --logpath E:\MongoDB\Server\data\shard\log\s2.log --directoryperdb --fork

(3) 启动 Config Server
mongod --configsvr --port 30000 --dbpath E:\MongoDB\Server\data\shard\config --logpath E:\MongoDB\Server\data\shard\log\config.log --directoryperdb --fork

(4) 启动 Route Process
mongos --port 40000 --configdb localhost:30000  --logpath E:\MongoDB\Server\data\shard\log\route.log --chunkSize 1 --fork
说明: chunkSize 这一项是用来指定 chunk 的大小的,单位是 MB,默认大小为 200MB

(5) 登录到 mongos,添加 Shard 节点
mongo admin --port 40000
> db.runCommand({ addshard:"localhost:20000" }) -- 添加shard server1
> db.runCommand({ addshard:"localhost:20001" })
> db.runCommand({ enablesharding:"test" }) --设置分片存储的数据库
> db.runCommand({ shardcollection: "test.users", key: { _id:1 }}) --设置分片的集合名称,且必须指定 Shard Key,系统会自动创建索引

> db.users.stats() -- 查看数据库分片情况
> db.runCommand({ listshards: 1 }) --列出所有的 Shard Server
> printShardingStatus() --查看 Sharding 信息
> db.runCommand({ addshard:"localhost:20002" }) --新增一个分片
> db.runCommand({"removeshard" : "localhost:20002"}) -- 可以间断地运行此命令,以查看其移除进度
 

posted @ 2016-11-13 20:00  一剑侵心  阅读(224)  评论(0编辑  收藏  举报