MongoDB学习总结

Posted 墨遥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB学习总结相关的知识,希望对你有一定的参考价值。

            前言:学习札记!

MongoDB学习总结(二)

1.  安装、初识

之前写过一篇MongoDB的快速上手文章,里边详细的讲了如何安装、启动MongoDB,这里就不再累述安装过程,简单介绍一下Mongodb的基本操作。

打开命令行窗口,输入“mongo”命令,默认会连接到test数据库。

Insert

db.person.insert("name":"Olive","age":18)

db.person.insert("name":"Momo","age":17)

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

"$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" ]

"无关键字“, "$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" ]

正则表达式匹配

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" ]

$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" ]

 

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

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

读写分离

在从属服务器中,执行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学习总结的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB按“数字”升序排列

mongoDB学习

MongoDB学习总结

MongoDB学习总结

哈希和升序索引之间的 Mongodb 性能差异(有啥理由不在无序字段中使用哈希?)

MongoDB升序/降序定位错误值