mongodb 快速学习总结

//mongodb学习总结
windows安装:
下载安装
在根目录建立数据库目录
d:\data\db
mongod --dbpath c:\data\db 启动数据库指定数据目录
作为windows服务
mongod.exe --bind_ip yourIPadress --logpath "C:\data\dbConf\mongodb.log" --logappend --dbpath "C:\data\db" --port yourPortNumber --serviceName "YourServiceName" --serviceDisplayName "YourServiceName" --install
启动后台mongod shell
到bin目录输入mongo
表==集合
记录==文档
列==字段/域


//创建数据库
use dbname


//查看数据库
show dbs


//删除数据库
db.dropDatabase()


//删除集合
db.collectionName.drop()


//插入文档
db.collectionName.insert(document)
插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。


//更新文档
db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,//不存在是否插入
     multi: <boolean>,
     writeConcern: <document>
   }
)


//例子
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})
//save方法通过传入的文档来替换已有文档。
db.collection.save(
   <document>,
   {
     writeConcern: <document>
   }
)


//删除文档
db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)


//只删除第一条
db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)


//删除所有数据
db.col.remove({})
remove() 方法已经过时了,现在官方推荐使用 deleteOne() 和 deleteMany() 方法
如删除集合下全部文档:
db.inventory.deleteMany({})
删除 status 等于 A 的全部文档:
db.inventory.deleteMany({status:"A"})
删除 status 等于 D 的一个文档:
db.inventory.deleteOne({status:"D"})


//查询文档
db.collection.find(query, projection)
MongoDB OR 条件语句使用了关键字 $or,语法格式如下:
db.col.find(
   {
      $or: [
         {key1: value1}, {key2:value2}
      ]
   }
).pretty()
//条件操作符
(>) 大于 - $gt
(<) 小于 - $lt
(>=) 大于等于 - $gte
(<= ) 小于等于 - $lte
$type操作符
$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果


//limit和skip方法
db.col.find({},{"title":1,_id:0}).limit(1).skip(1)
第一个 {} 放 where 条件,为空表示返回集合中所有文档。
第二个 {} 指定那些列显示和不显示 (0表示不显示 1表示显示)。
//效率问题
b.test.sort({"amount":1}).skip(100000).limit(10)  //183ms
db.test.find({amount:{$gt:2399927}}).sort({"amount":1}).limit(10)  //53ms
结果已经附带到注释了,很明显后者的性能是前者的三分之一,差距是非常大的。也印证了Skip效率差的理论


//排序sort方法
db.COLLECTION_NAME.find().sort({KEY:1/-1})


//索引ensureIndex()
db.COLLECTION_NAME.ensureIndex({KEY:1})


//多个字段创建索引
db.col.ensureIndex({"title":1,"description":-1})


//聚合方法
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])


//db复制
dbDB副本集设置
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
以上实例会启动一个名为rs0的MongoDB实例,其端口号为27017。
启动后打开命令提示框并连接上mongoDB服务。
在Mongo客户端使用命令rs.initiate()来启动一个新的副本集。
我们可以使用rs.conf()来查看副本集的配置
查看副本集状态使用 rs.status() 命令
添加副本集的成员,我们需要使用多台服务器来启动mongo服务。进入Mongo客户端,并使用rs.add()方法来添加副本集的成员。
假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。 
在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:
rs.add("mongod1.net:27017")
是否为主节点可以使用命令db.isMaster()。


//分片实例
分片结构端口分布如下:
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000
步骤一:启动Shard Server
[root@100 /]# mkdir -p /www/mongoDB/shard/s0
[root@100 /]# mkdir -p /www/mongoDB/shard/s1
[root@100 /]# mkdir -p /www/mongoDB/shard/s2
[root@100 /]# mkdir -p /www/mongoDB/shard/s3
[root@100 /]# mkdir -p /www/mongoDB/shard/log
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork
....
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend --fork
步骤二: 启动Config Server
[root@100 /]# mkdir -p /www/mongoDB/shard/config
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork
步骤三: 启动Route Process
/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500
//mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB
步骤四: 配置Sharding
接下来,我们使用MongoDB Shell登录到mongos,添加Shard节点
[root@100 shard]# /usr/local/mongoDB/bin/mongo admin --port 40000
MongoDB shell version: 2.0.7
connecting to: 127.0.0.1:40000/admin
mongos> db.runCommand({ addshard:"localhost:27020" })
{ "shardAdded" : "shard0000", "ok" : 1 }
......
mongos> db.runCommand({ addshard:"localhost:27029" })
{ "shardAdded" : "shard0009", "ok" : 1 }
mongos> db.runCommand({ enablesharding:"test" }) #设置分片存储的数据库
{ "ok" : 1 }
mongos> db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}})
{ "collectionsharded" : "test.log", "ok" : 1 }
步骤五: 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000


//备份(mongodump)与恢复(mongorestore)
mongodump -h dbhost -d dbname -o dbdirectory
mongorestore -h <hostname><:port> -d dbname <path>


//监控
mongostat 命令
mongotop 命令
D:\set up\mongodb\bin>mongostat
D:\set up\mongodb\bin>mongotop
E:\mongodb-win32-x86_64-2.2.1\bin>mongotop 10
E:\mongodb-win32-x86_64-2.2.1\bin>mongotop --locks


//mongod关系
直接嵌入关系
引用式关系
{
   "_id":ObjectId("52ffc33cd85242f436000001"),
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin",
   "address_ids": [
      ObjectId("52ffc4a5d85242602e000000"),
      ObjectId("52ffc4a5d85242602e000001")
   ]
}
//查询两次
>var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})


//一个文档从多个集合引用文档,我们应该使用 DBRefs
{ $ref : , $id : , $db :  }
三个字段表示的意义为:
$ref:集合名称
$id:引用的id
$db:数据库名称,可选参数
{
   "_id":ObjectId("53402597d852426020000002"),
   "address": {
   "$ref": "address_home",
   "$id": ObjectId("534009e4d852427820000002"),
   "$db": "w3cschoolcc"},
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin"
}
>var user = db.users.findOne({"name":"Tom Benzamin"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})


//使用覆盖索引查询
>db.users.ensureIndex({gender:1,user_name:1})
该索引会覆盖以下查询:
>db.users.find({gender:"M"},{user_name:1,_id:0})
//由于我们的索引中不包括 _id字段,_id在查询中会默认返回,我们可以在MongoDB的查询结果集中排除它
所有索引字段是一个数组或所有索引字段是一个子文档不能使用覆盖索引查询


//查询分析
>db.users.ensureIndex({gender:1,user_name:1})
>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()


//hint()
也可以使用 hint 来强制 MongoDB 使用一个指定的索引
db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()


//原子操作
$set
用来指定一个键并更新键值,若键不存在并创建。
{ $set : { field : value } }
$unset
用来删除一个键。
{ $unset : { field : 1} }
$inc
$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
{ $inc : { field : value } }
$push
用法:
{ $push : { field : value } }
把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。
$pushAll
同$push,只是一次可以追加多个值到一个数组字段内。
{ $pushAll : { field : value_array } }
$pull
从数组field内删除一个等于value值。
{ $pull : { field : _value } }
$addToSet
增加一个值到数组内,而且只有当这个值不在数组内才增加。
$pop
删除数组的第一个或最后一个元素
{ $pop : { field : 1 } }
$rename
修改字段名称
{ $rename : { old_field_name : new_field_name } }
$bit
位操作,integer类型
{$bit : { field : {and : 5}}}


//高级索引
索引数组字段
在数组中创建索引,需要对数组中的每个字段依次建立索引
db.users.ensureIndex({"tags":1})
索引子文档字段
db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})
记住查询表达式必须遵循指定的索引的顺序。
db.users.find({"address.city":"Los Angeles"}) 


//索引限制
查询限制
索引不能被以下的查询使用:
正则表达式及非操作符,如 $nin, $not, 等。
算术运算符,如 $mod, 等。
$where 子句
所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。
集合中索引不能超过64个
索引名的长度不能超过128个字符
一个复合索引最多可以有31个字段


//ObjectId
ObjectId 是一个12字节 BSON 类型数据,有以下格式:
前4个字节表示时间戳
接下来的3个字节是机器标识码
紧接的两个字节由进程id组成(PID)
最后三个字节是随机数。
生成新的ObjectId:
>newObjectId = ObjectId()
通过 getTimestamp 函数来获取文档的创建时间:
>ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()
将ObjectId转换为字符串格式:
>new ObjectId().str


//Map Reduce
MapReduce的基本语法:
>db.collection.mapReduce(
   function() {emit(key,value);},  //map 函数
   function(key,values) {return reduceFunction},   //reduce 函数
   {
      out: collection,
      query: document,
      sort: document,
      limit: number
   }
)
选取已发布的文章(status:"active"),并通过user_name分组,计算每个用户的文章数:
>db.posts.mapReduce( 
   function() { emit(this.user_name,1); }, 
   function(key, values) {return Array.sum(values)}, 
      {  
         query:{status:"active"},  
         out:"post_total" 
      }
)
以上 mapReduce 输出结果为:
{
        "result" : "post_total",
        "timeMillis" : 23,
        "counts" : {
                "input" : 5,
                "emit" : 5,
                "reduce" : 1,
                "output" : 2
        },
        "ok" : 1
}
结果表明,共有 5 个符合查询条件(status:"active")的文档,在map函数中生成了5 个键值对文档,最后使用reduce函数将相同的键值分为 2 组。
具体参数说明:
result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
timeMillis:执行花费的时间,毫秒为单位
input:满足条件被发送到map函数的文档个数
emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
ouput:结果集合中的文档个数(count对调试非常有帮助)
ok:是否成功,成功为1
err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大


//启用全文检索
db.adminCommand({setParameter:true,textSearchEnabled:true})
或者使用命令:
mongod --setParameter textSearchEnabled=true
我们可以对 post_text 字段建立全文索引:
>db.posts.ensureIndex({post_text:"text"})
查询
db.posts.find({$text:{$search:"runoob"}})
以下命令返回了如下包含 runoob 关键词的文档数据:

   "_id" : ObjectId("53493d14d852429c10000002"), 
   "post_text" : "enjoy the mongodb articles on Runoob", 
   "tags" : [ "mongodb", "runoob" ]
}
如果你使用的是旧版本的 MongoDB,你可以使用以下命令:
>db.posts.runCommand("text",{search:"runoob"})
删除全文索引
删除已存在的全文索引,可以使用 find 命令查找索引名:
>db.posts.getIndexes()
通过以上命令获取索引名,本例的索引名为post_text_text,执行以下命令来删除索引:
>db.posts.dropIndex("post_text_text")


//正则表达式
MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式


以下命令使用正则表达式查找包含 runoob 字符串的文章:
>db.posts.find({post_text:{$regex:"runoob"}})
以上查询也可以写为:
>db.posts.find({post_text:/runoob/})


以下命令将查找不区分大小写的字符串 runoob:
>db.posts.find({post_text:{$regex:"runoob",$options:"$i"}})


数组元素使用正则表达式
我们还可以在数组字段中使用正则表达式来查找内容。 这在标签的实现上非常有用,如果你需要查找包含以 run 开头的标签数据(ru 或 run 或 runoob), 你可以使用以下代码:
>db.posts.find({tags:{$regex:"run"}})


正则表达式中使用变量。一定要使用eval将组合的字符串进行转换,不能直接将字符串拼接后传入给表达式。否则没有报错信息,只是结果为空!实例如下:
var name=eval("/" + 变量值key +"/i"); 
以下是模糊查询包含title关键词, 且不区分大小写:
title:eval("/"+title+"/i")    // 等同于 title:{$regex:title,$Option:"$i"}


//GridFS
GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。
mongofiles.exe -d gridfs put song.mp3
GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。
使用以下命令来查看数据库中文件的文档:
>db.fs.files.find()
以上命令执行后返回以下文档数据:
{
   _id: ObjectId('534a811bf8b4aa4d33fdf94d'), 
   filename: "song.mp3", 
   chunkSize: 261120, 
   uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",
   length: 10401959 
}
我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据:
>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})
以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。


//创建固定集合
我们通过createCollection来创建一个固定集合,且capped选项设置为true:
>db.createCollection("cappedLogCollection",{capped:true,size:10000})
还可以指定文档个数,加上max:1000属性:
>db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})
判断集合是否为固定集合:
>db.cappedLogCollection.isCapped()
如果需要将已存在的集合转换为固定集合可以使用以下命令:
>db.runCommand({"convertToCapped":"posts",size:10000})
固定集合查询
固定集合文档按照插入顺序储存的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural调整返回顺序。
>db.cappedLogCollection.find().sort({$natural:-1})
固定集合的功能特点
可以插入及更新,但更新不能超出collection的大小,否则更新失败,不允许删除,但是可以调用drop()删除集合中的所有行,但是drop后需要显式地重建集合。
固定集合属性及用法
属性
属性1:对固定集合进行插入速度极快
属性2:按照插入顺序的查询输出速度极快
属性3:能够在插入最新数据时,淘汰最早的数据
用法
用法1:储存日志信息
用法2:缓存一些少量的文档


//自动增长
使用 counters 集合
考虑以下 products 文档。我们希望 _id 字段实现 从 1,2,3,4 到 n 的自动增长功能。
{
  "_id":1,
  "product_name": "Apple iPhone",
  "category": "mobiles"
}
为此,创建 counters 集合,序列字段值可以实现自动长:
>db.createCollection("counters")
现在我们向 counters 集合中插入以下文档,使用 productid 作为 key:
{
  "_id":"productid",
  "sequence_value": 0
}
sequence_value 字段是序列通过自动增长后的一个值。
使用以下命令插入 counters 集合的序列文档中:
>db.counters.insert({_id:"productid",sequence_value:0})
创建 Javascript 函数
现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid 。
>function getNextSequenceValue(sequenceName){
   var sequenceDocument = db.counters.findAndModify(
      {
         query:{_id: sequenceName },
         update: {$inc:{sequence_value:1}},
         new:true
      });
   return sequenceDocument.sequence_value;
}
使用 Javascript 函数
接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值:
>db.products.insert({
   "_id":getNextSequenceValue("productid"),
   "product_name":"Apple iPhone",
   "category":"mobiles"})


>db.products.insert({
   "_id":getNextSequenceValue("productid"),
   "product_name":"Samsung S3",
   "category":"mobiles"})
就如你所看到的,我们使用 getNextSequenceValue 函数来设置 _id 字段。
为了验证函数是否有效,我们可以使用以下命令读取文档:
>db.products.find()
以上命令将返回以下结果,我们发现 _id 字段是自增长的:
{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}
{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星月IWJ

曾梦想杖键走天涯,如今加班又挨

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值