前言:学习札记!
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 db.user.mapReduce(map,reduce,{“output”:“collection”}); Mongodb里的游标是申明一个查询结构,并没有出具体的数据,只有在遍历时才加载过来,通过游标读取,枚举完成之后销毁游标。 Varlist=db.user.find() list.Foreach(function(item){print(item.name);}); 同时在构造查询时,还可以根据需要进行复杂的查询构造,例如:分页、排序等 Varlist=db.user.find().sort({“name”,1}).skip(3).limit(3); 在数据库中插入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 } db.user.ensureIndex({“name”:1}); 利用ensureIndex方法为name字段添加索引,“1”表示照name升序,“-1”表示照name降序。 db.user.find({name:“墨遥”}).explain(); db.user.ensureIndex({"name":1},{"unique":true}) 创建唯一索引,重复的键就不能再插入。 多条件查询时,可以通过创建组合索引来加速查询。 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}); db.user.dropIndex(“name_1”) 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()即可支持从从属数据库读取信息 副本集也是属于主从集群,但是跟上边的集群有区别的。 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") 当数据量达到T级别的时候,mongodb采用将集合进行拆分,将拆分的数据分摊到几个片上。我们要了解”片键“的概念,也就是说拆分集合的依据是,按照键值进行拆分集合。这里需要一个路由服务器(mongos),根据管理员设置的“片键”将数据分摊到自己管理的mongod集群,同时需要一个config服务器,用来保存数据和片的对应关系以及相应的配置信息。同时还需要若干的mongodb服务器。具体实践如下: Config服务主要用来存储数据和片的对应关系,所应该最先开启。 --开启Config服务器 mongod --dbpath D:\SubMongoDB\Data --port 2222 Mongos服务器就是一个路由服务器,同时要为其指定config服务器 --开启mongos服务器 mongos --port 3333 --configdb 127.0.0.1:2222 --启动mongod服务器(4444,5555) mongod --dbpath D:\ThreeMongoDB\Data --port 4444 mongod --dbpath D:\FourMongoDB\Data --port 5555 --连接到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}) --开启数据库的分片功能 mongo 127.0.0.1:3333/admin db.runCommand({"enablesharding":"test"})—为test数据开启分片功能 --指定集合中分片的键 db.runCommand({"shardcollection":"test.user","key":{"name":1}})—指定test数据库中user集合的name为片键 通过mongos向mongodb中插入10w数据,并通过db.printShardingStatus()来查看效果 插入的1万条数据分布在4444和5555服务器上。 Mongod –dbpath D:\MongoDB\Data –-logpath D:\MongoDB\Log\log.txt–port 2222 –install 设置MongoDB数据存储路径,日志路径,同时开启了安装服务寄宿。 通过db.serverStatus()来查看服务器的统计信息(全局锁、索引、用户操作行为等) 通过mongostat实时刷新,观看数据实时变化。 Mongostat –port 3333 Use admin Db.system.users.remove({“user”:”XXX”}) 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() 官网驱动示例:(从官网下载Mongodb.net 的驱动) App.config内容: 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 QueryDocument query = new QueryDocument { { "Name", name } }; var list = collection.FindAs 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 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 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 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 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 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 foreach (var u in list) { Console.WriteLine("Name: {0}, Sex: {1}, Age: {2}, Code: {3}", u.Name,u.Sex, u.Age, u.Code); } } } } 3. 游标
4. 索引
4.1 性能分析函数(explain)
4.2 建立索引(ensureIndex)
4.3 唯一索引
4.4 组合索引
4.5 删除索引
5. 主从复制
6. 副本集
7. 分片
7.1 开启config服务器
7.2 开启mongos服务器
7.3 添加mongodb服务器(也就是要添加的片)
7.4 连接到mongos服务器并将mongodb服务添加分片
7.5 mongos服务器设置片键切分数据
7.6 插入数据,查看效果
8. 安装部署
9. 状态监控
10. 安全认证
11. 备份和恢复
12. 驱动示例