启动与停止

启动mongodb

  • 一般情况:mongod --dbpath=./ --port 27017
  • 全网络访问:mongod --dbpath=./ --port 27017 --bind_ip_all

停止mongodb

  1. use admin;
  2. db.shutdownServer();

常用命令

进入命令行模式

在终端直接输入 mongo 即可。

数据库切换

  • 显示当前的数据库: show dbs
  • 切换数据库: use <数据库名>
  • 显示当前数据库中的集合: show collections

查询

基本的查询

  • 查询所有:db.foo.find()
  • 指定需要返回的键:
    1. db.users.find({},{"username":1}); // 通过find()的第二个参数确定,这个参数中的数字为1则显示,为0则排除。如果两个都存在,则在1的基础上排除0。

查询条件

  • 比较操作符
    • $lt、$lte、$gt和$gte,分别对应<、<=、>、>=
      • 查询18-30岁(含)的用户:db.users.find({"age":{"$gte":18,"$lte":30}})
    • $ne表示不相等
      • 查询所有名字不为joe的用户:db.users.find({"username":{"$ne":"joe"}})
  • OR查询
    • $in可以用来查询一个键的多个值(可以指定不同类型的条件和值)
      • 找出4个与中奖号码匹配的文档:db.raffle.find({"ticket_no":{"$in":[725,542,390,391]}})
      • 匹配user_id等于123456的文档:db.users.find({"user_id":{"$in":[12345,"joe"]}}) // 同时也会匹配user_id等于joe的文档
      • 与$in相对的是$nin,它可以返回所有不匹配的的文档。
    • $or更通用一些,可以在多个键中查询任意的给定值
      • 例如:db.raffle.find({"$or":[{"ticket_no":725},{"winner":true}]})
      • 例如:db.raffle.find({"$or":[{"ticket_no":{"$in":[725,542,390]}},{"winner":true}]})
      • 使用普通的AND型查询时,总是希望尽可能用最少的条件来限定结果的范围。OR型查询正相反:第一个条件应该尽可能匹配更多的文档,这样才是最为高效的。
  • $not查找与特定模式不匹配的文档(与正则表达式联合使用极为有用)
    • 例如:db.users.find({"id_num":{"$not":{"$mod":[5,1]}}})

特定类型的查询

  • 查询结果为键值null的文档

    1. db.c.find({"z":null}) // 它会查询z的值为null的文档,同时也会查询到没有z这个键的文档`
    2. db.c.find({"z":{"$in":[null],"$exists":true}}) // 它仅仅会查询z的值为null的文档`
  • 正则表达式

    • 例如:db.users.find({"name":/joe?/i})
    • 假如正则表达式被插入到的文档当中,也可以通过find查询到自身。(应该是被当作字符串处理了)
  • 查询数组

    • 最基本

      1. db.food.insert({"fruit":["apple","banana","peach"]})
      2. db.food.find({"fruit":"banana"}) // 它可以成功匹配到上面的文档
    • $all通过多个元素来匹配数组

      • 假如已有三个元素的集合:

        1. db.food.insert({"_id":1,"fruit":["apple","banana","peach"]})
        2. db.food.insert({"_id":2,"fruit":["apple","banana","peach"]})
        3. db.food.insert({"_id":3,"fruit":["apple","banana","peach"]})
      • 查找既有”apple”又有”banana”的文档:

        • db.food.find({fruit:{$all:["apple","banana"]}}) // 这里的顺序是不重要的
    • 精准匹配

      1. db.food.insert({"fruit":["apple","banana","peach"]}) // 已有文档
      2. db.food.find({"fruit":["apple","banana","peach"]}) // 可以匹配到
      3. db.food.find({"fruit":["apple","banana"]}) // 匹配不到
      4. db.food.find({"fruit":["banana","apple","peach"]}) // 匹配不到
    • 通过数组下标查询

      1. db.food.insert({"fruit":["apple","banana","peach"]}) // 已有文档
      2. db.food.find({"fruit.2":"peach"}) // 数组下标都是从0开始的
    • $size可以用来查询特定长度的数组

      • 例如:db.food.find({"fruit":{"$size":3}})
    • $slice可以返回某个键匹配的数组元素的一个子集(find的第二个参数是指定需要返回的键)

      1. db.blog.posts.findOne(criteria,{"comments":{"$slice":10}}) // 返回前10条评论
      2. db.blog.posts.findOne(criteria,{"comments":{"$slice":-10}}) // 返回后10条评论
      3. db.blog.posts.findOne(criteria,{"comments":{"$slice":[23,10]}}) // 跳过前23个元素,返回第24-33个元素。如果数组不够33个元素,则返回第23个元素后面的所有元素。
    • 返回一个匹配的数组元素

      • db.blog.posts.find({"comments.name":bob},{"comments.$":1}) // 返回众多评论中的第一条数据,其结果依然是数组形式的。
    • $elemMatch要求同时使用查询条件中的多条语句与一个数组进行比较

      • 数组和范围查询的互相作用

        • 假如已有四个元素的集合:

          1. {"x":5}
          2. {"x":15}
          3. {"x":25}
          4. {"x":[5,25]}
        • 查找10-20之间的数组:

          1. db.test.find({"x":{"$gt":10,"$lt":20}}) // 错误的,它返回的是上面第2和第4个文档
          2. db.test.find({"x":{"$eleMatch":{"$gt":10,"$lt":20}}}) // 只返回第4个文档
          3. db.test.find({"x":{"$gt":10,"$lt":20}}).min({"x":10}).max({"x":20}) //通过索引限定范围可以只返回第3个文档
      • 查询内嵌文档

        • 假如db.blog集合中有以下数据:

          1. {"content":"…","comments":[{"author":"joe","score":3,"comment":"nice post"},{"author":"mary","score":6,"comment":"terrible post"}]}
        • 查找joe发表的5分以上的评论

          • 不能使用db.blog.find({"comments":{"author":"joe","score":{"$gte":5}}})来查询,因为内嵌文档的匹配,必须要整个文档完全匹配,而这个查询不会匹配”comment”键。
          • 使用db.blog.find({"comments.author":"joe","comments.score":{"$gte":5}})也不行,因为符合author条件的评论和符合score条件的评论可能不是同一条评论。
          • 正确方式:db.blog.find({"comments":{"$elemMatch":{"author":"joe","score":{"$gte":5}}}})

游标

  • 排序sort
    • db.c.find().sort({username:1,age:-1}) // 1剩序、2倒序,如果指定了多个键,则按照这些键被指定的顺序诸葛排序。
  • 限定返回结果数量limit
    • db.c.find().limit(3) // 返回3个结果,这里的数量是上限,所以少于3时,该显示几个结果就是几个结果
  • 略过一定数量skip
    • db.c.find().skip(3) // 如果集合里能匹配的文档少于3个,这不会返回任何文档。

查看查询语句执行效率

  • 示例:db.c.find().explain()
  • 各字段含义:
    • millis:查询的执行速度,单位毫秒。
    • n:实际返回的文档数量
    • nscanned:反映了在执行这个查询过程中搜索了多少索引条目
    • nscannedObjects:反映了在执行这个查询过程中扫描的文档数量
    • scanAndOrder:MongoDB不得不在内存中对结果进行排序时会返回true
    • isMultiKey:用于说明本次查询是否使用了多键索引
    • indexOnly:是否只使用索引就完成了此次查询。查询的内容都是索引指定的字段,包括_id才会返回true。
    • nYields:为了让写入请求能够顺利执行,本次查询暂停的次数。
    • indexBounds:这个字段描述了索引的使用情况,给出了索引的遍历范围。
    • cursor
      • 示例:”cursor”:”BtreeCursor age_1_username_1”
      • BtreeCursor表示本次查询使用了索引,具体来看使用了age和username进行了顺序排序
      • 如果包含reverse表示对结果进行了逆序排列
      • 如果包含multi表示使用了多键索引

插入

  • 单个:db.foo.insert({"bar":"baz"})
  • 批量:db.foo.batchInsert([{"_id":0},{"_id":1},{"_id":2}])

删除

  • 删除文档所有数据:db.foo.remove()
  • 删除特定条件的数据:db.foo.remove({"opt-out":true})
  • 删除集合:db.foo.drop()

更新

  • 文档替换(全部替换)
    • db.users.update({"name":"joe"},jsonObj); // 用jsonObj的数据一股脑的替换掉原有数据
    • 因为搜索出来的可能是多条数据,且_id也会替换进去,很容易出现重复_id的错误,所以尽量使用_id作为查询条件去替换。
  • 修改器替换(局部更新)
    • 修改器是种特殊的键,用来指定复杂的更新操作,比如修改、增加或者删除,还可能是操作数组或者内嵌文档。
    • 常见修改器
      • $set:用来指定一个字段的值。如果这个字段不存在,则创建它。
        • db.users.update({"_id":ObjectId("46849848")},{"$set":{"name":"chenhao"}})
      • $unset:删除指定的字段
        • db.users.update({"name":"chenhao"},{"$unset":{"age":1}}); //后面指定的值不影响$unset表达式执行
      • $inc:增加or减少已有值。如果这个字段不存在,则创建它。(只对数字类型的字段有效)
        • db.analytics.update({"url":"www.xjchenhao.cn"},{"$inc":{"pageviews":1}}) // 后面的数字是控制增加or减少的大小
    • 数组修改器
      • $push:向已有的数组末尾加入一个值,要是没有就创建一个新的数组。
        • db.blog.posts.update({"title":"i am title"},{"$push":{"comments":{"content":"i am content"}}})
        • 插入多个值:db.stock.ticker.update({"_id":"Goog"},{"$push":{"hourly":{"$each":[1,2,3,4]}}})
        • 保留最后加入的几个值:db.movies.update({"name":"chenhao"},{"$push":{"top10":{"$each":[1,2,3],"$slice":-10}}}) // 如果数组长度大于10则保留最新10个,如果小于则全部保留(注意是负数)
        • 排序后保留最后的几个值:db.movies.update({"name":"chenhao"},{"$push":{"top10":{"$each":[1,9,3,4],"$slice":-2,"$sort":{"top10":-1}}}})
      • $addToSet:类似$push,但是它可以确保数组内的元素不会重复。
      • $pop:从数组任意一端删除值
        • db.lists.update({},{"$pop":{"key":3}}); // 正数时从末尾开始删除,负数时从头部开始删除
      • $pull:根据条件删除数组元素
        • db.lists.update({},{{$pull:{"todo":"数组元素"}}})
      • 删除指定位置的数组元素:
        • 可以通过指定数组的下标:db.blog.update({"post":1},{"$inc":{"comments.0.votes":1}})
        • 可以通过$修改不确定下标的元素:db.blog.update({"comments.author":"john"},{"$set":{"comments.$.author":"jim"}})
  • 查看最后一次操作的相关信息:db.runCommand({getLastError:1})

导入导出

  • 导出:mongodump -h dbhost -d dbname -o dbdirectory
    • -h:MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017
    • -d:需要备份的数据库实例,例如:test
    • -o:备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。
  • 导入:mongorestore -h dbhost -d dbname --directoryperdb dbdirectory
    • -h:MongoDB所在服务器地址
    • -d:需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2
    • —directoryperdb:备份数据所在位置,例如:c:\data\dump\test,这里为什么要多加一个test,而不是备份时候的dump,读者自己查看提示吧!
    • —drop:恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!

更新的传参和返回值

  1. model.update(conditions, doc, option, function (err, res){})
  2. // conditions-查询条件 doc-需要更新的数据
  3. *** 其中res返回 {n:2, nModified:2, ok: 1} ***
  4. *** n为匹配到的条数 nModified修改的条数 ok 表为是否成功 ***
  5. const option = { // option选项及其默认值
  6. safe: true, // 安全模式
  7. upsert: false, //如果不存在则创建新纪录
  8. multi: false, // 是否更新多个查询记录
  9. runValidators: null, // 如果值为true,执行Validation验证。
  10. setDefaultsOnInsert: null, // 如果upsert选项为true,在新建时插入文档定义的默认值。
  11. strict: null, // 用严格模式跟新
  12. overwrite: false // 禁用update-only模式,允许覆盖记录。
  13. }

表结构修改

修改字段名

  1. db.columnsample.updateMany(
  2. {},
  3. {
  4. "$rename":{"oldFieldName":"newFieldName"}
  5. }
  6. )

字段类型

  • NumberInt:整数数字

索引管理

新增

新的
  1. db.collection.ensureIndex(keys, options)

旧的
  1. db.collection.createIndex(keys, options)

注意:1.8版本之前创建索引使用createIndex(),1.8版本之后已移除该方法

示例

  1. db.addresses.ensureIndex( { "xmpp_id": 1 }, { sparse: true } )

这个示例,那些不包含xmpp_id的键(列)的文档将不会被索引

查看

当前集合的索引
  1. db.collection.getIndexes()

查看数据库中所有索引
  1. db.system.indexes.find()

删除

删除指定的索引
  1. db.collection.dropIndex("INDEX-NAME")

删除所有索引
  1. db.collection.dropIndexes()

如果发现MongoDB使用的索引与自己希望它使用的索引不一致,可以使用hint()强制MongoDB使用特定的索引。

  • 强制使用索引:db.c.find({"age":1,"username":/.*/}).hint({"username":1,"age":1})
  • 强制使用全表查询:db.c.find({"age":1,"username":/.*/}).hint({"$natural":1})

MAC的config

通过设置.mongorc.js文件设置初始化脚本

  • mac上的目录地址
    • ~/.mongorc.js
  • 启动shell时指定--norc参数,就可以禁止加载.mongorc.js
  • 代码示例

    • 设置防止删除数据的操作。

      1. var no=()=>{print(‘Not on my watch.’)};
      2. db.dropDatabase=DB.prototype.dropDatabase=no;
      3. DBCollection.prototype.drop=no;
      4. DBCollection.prototype.dropIndex=no;
    • 获得最后一次操作完成的时间

      1. prompt=function(){
      2. return (new Date())+'> ';
      3. }
    • 显示当前使用的数据库

      1. prompt = function () {
      2. if (typeof db === 'undefined') {
      3. return '(nodb)> ';
      4. }
      5. try {
      6. db.runCommand({ getLastError: 1 });
      7. }
      8. catch (e) {
      9. print(e);
      10. }
      11. return db + '> ';
      12. }

注:3.2版本后停止使用HTTP interface,无法使用28017端口查看数据库的管理信息了。
_

集群搭建