MongoDB学习总结
Posted 墨遥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB学习总结相关的知识,希望对你有一定的参考价值。
前言:学习札记!
MongoDB学习总结(二)
1. 安装、初识
之前写过一篇MongoDB的快速上手文章,里边详细的讲了如何安装、启动MongoDB,这里就不再累述安装过程,简单介绍一下Mongodb的基本操作。
打开命令行窗口,输入“mongo”命令,默认会连接到test数据库。
l Insert
db.person.insert("name":"Olive","age":18)
db.person.insert("name":"Momo","age":17)
l find
db.person.find()//查找所有的person数据
"_id" :ObjectId("58a03991d57e6773c574e485"), "name" :"Olive", "age" : 18
"_id" :ObjectId("58a039a8d57e6773c574e486"), "name" :"Momo", "age" : 17
db.person.find("name":"Olive")//查找名为Olive的person数据
"_id" :ObjectId("58a03991d57e6773c574e485"), "name" :"Olive", "age" : 18
u "$gt","$gte", "$lt", "$lte", "$ne", "没有特殊关键字"(对应的为>,>=,<,<=,!=)
db.user.find("age":$gt:22)//年龄大于22
"_id" : ObjectId("58a03dc7d57e6773c574e488"),"name" : "joe", "password" : "123456","age" : 25, "address" : "province" :"henan", "city" : "zhengzhou" ,"favourite" : [ "money", "girl" ]
db.user.find("age":$lt:22)//年龄小于22
"_id" :ObjectId("58a03cc0d57e6773c574e487"), "name" :"jack", "password" : "123456", "age" :20, "address" : "province" : "beijing","city" : "chaoyang" , "favourite" : ["apple", "banana" ]
db.user.find("age":$ne:25)//年龄不等于25
"_id" :ObjectId("58a03cc0d57e6773c574e487"), "name" :"jack", "password" : "123456", "age" :20, "address" : "province" : "beijing","city" : "chaoyang" , "favourite" : ["apple", "banana" ]
u "无关键字“, "$or", "$in","$nin"
db.user.find($or:["name":"jack","age":25])//名字为jack或age为25的user
"_id" :ObjectId("58a03cc0d57e6773c574e487"), "name" :"jack", "password" : "123456", "age" :20, "address" : "province" : "beijing","city" : "chaoyang" , "favourite" : ["apple", "banana" ]
"_id" :ObjectId("58a03dc7d57e6773c574e488"), "name" :"joe", "password" : "123456", "age" :25, "address" : "province" : "henan","city" : "zhengzhou" , "favourite" : ["money", "girl" ]
db.user.find("address.city":$in:["chaoyang","zhengzhou"])//城市为chaoyang或zhengzhou的user
"_id" :ObjectId("58a03cc0d57e6773c574e487"), "name" :"jack", "password" : "123456", "age" :20, "address" : "province" : "beijing","city" : "chaoyang" , "favourite" : ["apple", "banana" ]
"_id" :ObjectId("58a03dc7d57e6773c574e488"), "name" :"joe", "password" : "123456", "age" :25, "address" : "province" : "henan","city" : "zhengzhou" , "favourite" : ["money", "girl" ]
db.user.find("address.city":$nin:["chaoyang1","zhengzhou"])//查找城市不是chaoyang1或不是zhengzhou的user
"_id" :ObjectId("58a03cc0d57e6773c574e487"), "name" :"jack", "password" : "123456", "age" :20, "address" : "province" : "beijing","city" : "chaoyang" , "favourite" : ["apple", "banana" ]
u 正则表达式匹配
db.user.find($or:["name":/^j/,"name":/e$/])//匹配名字以j开头或者名字以e结尾的user
"_id" :ObjectId("58a03cc0d57e6773c574e487"), "name" :"jack", "password" : "123456", "age" :20, "address" : "province" : "beijing","city" : "chaoyang" , "favourite" : ["apple", "banana" ]
"_id" :ObjectId("58a03dc7d57e6773c574e488"), "name" :"joe", "password" : "123456", "age" :25, "address" : "province" : "henan","city" : "zhengzhou" , "favourite" : ["money", "girl" ]
u $where
db.user.find($where:function()return this.name=="joe")//用$where的方式查询名为joe的user
"_id" :ObjectId("58a03dc7d57e6773c574e488"), "name" :"joe", "password" : "123456", "age" :25, "address" : "province" : "henan","city" : "zhengzhou" , "favourite" : ["money", "girl" ]
l Update
db.person.update("name":"Olive","name":"Olive116","age":19)//更新名为Olive的person信息
u $inc 修改器(自增$inc指定的值,如果“文档”中没有此key,则会创建key,局部修改)
db.user.update("name":"jack",$inc:"age":10)
u $set修改器(局部修改age值)
db.user.update("name":"jack",$set:"age":10)
u upsert操作(如果没有查到,就在数据库里面新增一条)
db.user.update("name":"jackson",$inc:"age":1,true)//更新名为jackson的age值,如果该user不存在,则新增一条user信息
u 批量更新
db.user.update(“name”:“hxf”,$inc:“age”:10,true)//批量更新名为hxf的user
l remove
db.person.remove("name":"Momo")//移除名为Momo的person信息
2. 聚合
2.1count
db.user.count("age":25)//统计age为25的user个数
2.2distinct
db.user.distinct("age")
2.3group
db.user.group("key":"age":true,"initial":"person":[],"$reduce":function(cur,prev)prev.person.push(cur.name);)
key: 这个就是分组的key,我们这里是对年龄分组。
initial: 每组都分享一个”初始化函数“,特别注意:是每一组,比如这个的age=20的value的list分享一个initial函数,age=22同样也分享一个initial函数。
$reduce: 这个函数的第一个参数是当前的文档对象,第二个参数是上一次function操作的累计对象,第一次为initial中的”perosn“:[]。有多少个文档, $reduce就会调用多少次。
结果:
[
"age" : 10,
"person" : [
"jack"
]
,
"age" : 25,
"person" : [
"joe"
]
,
"age" : 1,
"person" : [
"jackson"
]
]
db.user.group("key":"age":true,"initial":"person":[],"reduce":function(doc,out)out.person.push(doc.name);,"finallize":function(out)out.count=out.person.length;,"condition":"age":$lt:25)
user数组里面的人员太多,想加上一个count属性标明一下。
针对上面的需求,在group里面还是很好办到的,因为group有这么两个可选参数: condition 和 finalize。
condition: 这个就是过滤条件。
finalize:这是个函数,每一组文档执行完后,多会触发此方法
结果:
[
"age" : 10,
"person" : [
"jack"
]
,
"age" : 1,
"person" : [
"jackson"
]
]
2.4mapReduce
mapReduce其实是一种编程模型,用在分布式计算中,其中有一个“map”函数,一个”reduce“函数。
l map:
这个称为映射函数,里面会调用emit(key,value),集合会按照你指定的key进行映射分组。
l reduce:
这个称为简化函数,会对map分组后的数据进行分组简化,注意:在reduce(key,value)中的key就是
emit中的key,vlaue为emit分组后的emit(value)的集合,这里也就是很多"count":1的数组。
l mapReduce:
这个就是最后执行的函数,参数为map,reduce和一些可选参数
mapfunction() emit(this.name,count:1);
reducefunction(key,value) var result=count:0; for(var i=0;i<value.length;i++)result.count+=value[i].count;return result;
db.user.mapReduce(map,reduce,“output”:“collection”);
3. 游标
Mongodb里的游标是申明一个查询结构,并没有出具体的数据,只有在遍历时才加载过来,通过游标读取,枚举完成之后销毁游标。
Varlist=db.user.find()
list.Foreach(function(item)print(item.name););
同时在构造查询时,还可以根据需要进行复杂的查询构造,例如:分页、排序等
Varlist=db.user.find().sort(“name”,1).skip(3).limit(3);
4. 索引
4.1 性能分析函数(explain)
在数据库中插入10万条数据,如下:
for(vari=0;i<1000000;i++)
...var rand=parseInt(i*Math.random());
...db.user.insert("name":"HXF"+i,"age":i)
...
查找一条数据,并利用“explain”分析函数,进行查询分析。
db.user.find("name":"HXF9999").explain()
"queryPlanner" :
"plannerVersion" : 1,
"namespace" :"test.user",
"indexFilterSet" :false,
"parsedQuery" :
"name" :
"$eq": "HXF9999"
,
"winningPlan" :
"stage" :"COLLSCAN",
"filter" :
"name" :
"$eq" : "HXF9999"
,
"direction" :"forward"
,
"rejectedPlans" : [ ]
,
"serverInfo" :
"host" :"WIN-GJ07N56QAK7",
"port" : 27017,
"version" :"3.0.6",
"gitVersion" :"1ef45a23a4c5e3480ac919b28afcba3c615488f2"
,
"ok" : 1
4.2 建立索引(ensureIndex)
db.user.ensureIndex(“name”:1);
利用ensureIndex方法为name字段添加索引,“1”表示照name升序,“-1”表示照name降序。
db.user.find(name:“墨遥”).explain();
4.3 唯一索引
db.user.ensureIndex("name":1,"unique":true)
创建唯一索引,重复的键就不能再插入。
4.4 组合索引
多条件查询时,可以通过创建组合索引来加速查询。
db.user.ensureIndex("name":1,"birthday":1)
创建组合索引,按照name升序,birthday升序。升序和降序的不同都会产生不同的索引。
我们可以通过getindexes来查看user下创建的所有索引。
db.user.getIndexes();
查询优化器在做查询时,会使用我们建立的这些索引来创建查询方案,如果某一个先执行完则其他查询方案被close掉,这种方案会被mongodb保存起来,当然如果非要用自己指定的查询方案,这也是可以的,在mongodb中给我们提供了hint方法让我们可以暴力执行。
db.user.find(name:‘HXF’,age:27).hint(age:1,name:1);
4.5 删除索引
db.user.dropIndex(“name_1”)
5. 主从复制
Mongodb主从复制的部署架构可以实现数据的备份、数据恢复、读写分离。
部署实践:
在一台服务器上启动Mongodb并将该数据库指定为主数据库,命令如下:
mongod --dbpath D:\\MangoDB\\Data –master
在另一台服务器上启动mongodb并将该数据库指定为从数据库,命令如下:
mongod –dbpath E:\\MongoDB\\Data –-slave –source=主服务器IP:27017
动态的添加从属服务器:
在新增的mongodb服务器上,使用local数据库,并在sources中添加一个host
地址,如下:
在新的mongodb服务器上启动mongodb数据库,
use local
db.sources.insert(“host”:”主服务器Ip:端口”);//127.0.0.1:27017
l 读写分离
在从属服务器中,执行rs.slaveOk()即可支持从从属数据库读取信息
6. 副本集
副本集也是属于主从集群,但是跟上边的集群有区别的。
l 副本集的集群没有特定的主数据库
l 如果某个主数据库宕机了,集群会自动推选一个从属数据库作为主数据库顶上,具备了自动故障恢复功能。
实践如下:
创建集群,启动D盘的mongodb程序,指定端口2222,,其中集群的名字为HXFX,--replSet表示告知服务器HXFX集群下还有其他的数据库(即指定的端口3333的数据库)
mongod--dbpath D:\\MongoDB\\Data --port 2222 --replSet HXFX/127.0.0.1:3333
打开端口为3333的数据库
mongod--dbpath D:\\SubMongoDB\\Data --port 3333 --replSet HXFX/127.0.0.1:2222
连接到任意一台服务器,并以admin登录数据库,进行副本集的初始化,命令如下:
mongo127.0.0.1:2222/admin
rs.runCommand("replSetInitiate":"_id":"HXFX","members":["_id":1,"host":"127.0.0.1:2222","_id":2,"host":"127.0.0.1:3333"])
新增一台服务器,作为仲裁服务器,如下:
mongod--dbpath D:\\ThreeMongoDB\\Data --port 4444 --replSet HXFX/127.0.0.3:2222
然后我们在admin集合中使用rs.addArb()追加即可。如下:
rs.addArb("127.0.0.1:4444")
7. 分片
当数据量达到T级别的时候,mongodb采用将集合进行拆分,将拆分的数据分摊到几个片上。我们要了解”片键“的概念,也就是说拆分集合的依据是,按照键值进行拆分集合。这里需要一个路由服务器(mongos),根据管理员设置的“片键”将数据分摊到自己管理的mongod集群,同时需要一个config服务器,用来保存数据和片的对应关系以及相应的配置信息。同时还需要若干的mongodb服务器。具体实践如下:
7.1 开启config服务器
Config服务主要用来存储数据和片的对应关系,所应该最先开启。
--开启Config服务器
mongod --dbpath D:\\SubMongoDB\\Data --port 2222
7.2 开启mongos服务器
Mongos服务器就是一个路由服务器,同时要为其指定config服务器
--开启mongos服务器
mongos --port 3333 --configdb 127.0.0.1:2222
7.3 添加mongodb服务器(也就是要添加的片)
--启动mongod服务器(4444,5555)
mongod --dbpath D:\\ThreeMongoDB\\Data --port 4444
mongod --dbpath D:\\FourMongoDB\\Data --port 5555
7.4 连接到mongos服务器并将mongodb服务添加分片
--连接到mongods服务器并将(4444,5555)服务器添加分片
mongo 127.0.0.1:3333/admin
db.runCommand("addshard":"127.0.0.1:4444",allowLocal:true)
db.runCommand("addshard":"127.0.0.1:5555",allowLocal:true)
7.5 mongos服务器设置片键切分数据
--开启数据库的分片功能
mongo 127.0.0.1:3333/admin
db.runCommand("enablesharding":"test")—为test数据开启分片功能
--指定集合中分片的键
db.runCommand("shardcollection":"test.user","key":"name":1)—指定test数据库中user集合的name为片键
7.6 插入数据,查看效果
通过mongos向mongodb中插入10w数据,并通过db.printShardingStatus()来查看效果
插入的1万条数据分布在4444和5555服务器上。
8. 安装部署
Mongod –dbpath D:\\MongoDB\\Data –-logpath D:\\MongoDB\\Log\\log.txt–port 2222 –install
设置MongoDB数据存储路径,日志路径,同时开启了安装服务寄宿。
9. 状态监控
通过db.serverStatus()来查看服务器的统计信息(全局锁、索引、用户操作行为等)
通过mongostat实时刷新,观看数据实时变化。
Mongostat –port 3333
10. 安全认证
Use admin
Db.system.users.remove(“user”:”XXX”)
11. 备份和恢复
Mongodump和mongorestore内置工具,保证不关闭服务器仍能copy数据。使用如下:
Mongodump -–port2222 –d test –o D:\\MongoDB\\Backup
将test数据库备份到D盘的mongoDB文件夹下的Backup文件夹下
Mongorestore–-port 2222 –d test –-drop D:\\MongoDB\\Backup\\test
将D:\\MongoDB\\Backup\\test还原到test数据库,并删除备份文件
通过加锁和释放锁的方式保证数据,能够全部的备份下来
db.runCommand("fsync":1,"lock":1)
释放锁: db.$cmd.unlock.findOne()
12. 驱动示例
官网驱动示例:(从官网下载Mongodb.net 的驱动)
App.config内容:
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<appSettings><!—配置连接字符串、数据库-->
<add key="ConnString" value="mongodb://127.0.0.1:27017"/>
<add key="DataBase" value="HXFDB"/>
</appSettings>
</configuration>
public staticclass MongoDBFactory
privatestatic string conn = ConfigurationManager.AppSettings["ConnString"];
privatestatic string database = ConfigurationManager.AppSettings["DataBase"];
private static MongoClient client = new MongoClient(conn);
privatestatic MongoServer server = client.GetServer();
privatestatic MongoDatabase db = server.GetDatabase(database);
//增
public static void Insert(string name)
MongoCollection collection = db.GetCollection("User");
User user = new User() ID = 0, Name = name, Sex = "男", Age = 27, Code = "MY001" , _id=newBson.ObjectId();
collection.Insert<User>(user);
QueryDocument query = new QueryDocument "Name", name ;
var list = collection.FindAs<User>(query);
foreach (var u in list)
Console.WriteLine("Name: 0, Sex: 1, Age: 2, Code: 3", u.Name,u.Sex, u.Age, u.Code);
//改
publicstatic void Update1(string name)
MongoCollection collection = db.GetCollection("User");
QueryDocument query = new QueryDocument "Name",name;
IMongoUpdate update = Update.Set("Code", "Olive001");
collection.Update(query,update);
var list = collection.FindAllAs<User>();
foreach (var u in list)
Console.WriteLine("Name: 0, Sex: 1, Age: 2, Code: 3", u.Name,u.Sex, u.Age, u.Code);
//删
publicstatic void Remove(string name)
MongoCollection collection = db.GetCollection("User");
QueryDocument query = new QueryDocument "Name", name ;
collection.Remove(query);
var list = collection.FindAllAs<User>();
foreach (var u in list)
Console.WriteLine("Name: 0, Sex: 1, Age: 2, Code: 3", u.Name,u.Sex, u.Age, u.Code);
//查
publicstatic void Query()
MongoCollection collection = db.GetCollection("User");
Console.WriteLine("SELECT * FROM table ");
//SELECT * FROM table
var list = collection.FindAllAs<User>();
foreach (var u in list)
Console.WriteLine("Name: 0, Sex: 1, Age: 2, Code: 3", u.Name,u.Sex, u.Age, u.Code);
Console.WriteLine("SELECT * FROM table WHERE Uid > 10 AND Uid< 20");
// sql : SELECT * FROM table WHERE Uid > 10 AND Uid < 20
QueryDocument query = new QueryDocument ;
BsonDocument bd=new BsonDocument ();
bd.Add("$gte",0);
bd.Add("$lt",5);
query.Add("ID", bd);
list = collection.FindAs<User>(query);
foreach (var u in list)
Console.WriteLine("Name: 0, Sex: 1, Age: 2, Code: 3", u.Name,u.Sex, u.Age, u.Code);
Console.WriteLine("SELECT Name FROM table WHERE Uid > 10 AND Uid< 20");
// SELECT Name FROM table WHERE Uid > 10 AND Uid < 20
FieldsDocument f = new FieldsDocument();
f.Add("Name", 1);
list = collection.FindAs<User>(query).SetFields(f);
foreach (var u in list)
Console.WriteLine("Name: 0", u.Name);
Console.WriteLine("SELECT * FROM table ORDER BY Uid DESC LIMIT10,10");
//SELECT * FROM table ORDER BY Name DESC LIMIT 10,10
SortByDocument s = new SortByDocument();
s.Add("Name", -1);
list = collection.FindAs<User>(query).SetSortOrder(s).SetSkip(1).SetLimit(10);
foreach (var u in list)
Console.WriteLine("Name: 0, Sex: 1, Age: 2, Code: 3", u.Name,u.Sex, u.Age, u.Code);
以上是关于MongoDB学习总结的主要内容,如果未能解决你的问题,请参考以下文章