MongoDB

Posted East-L

tags:

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

一 简介

MongoDB是一款强大、灵活、且易于扩展的通用型数据库

1、易用性

MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。
不采用关系型主要是为了获得更好得扩展性。当然还有一些其他好处,与关系数据库相比,面向文档的数据库不再有“行“(row)的概念取而代之的是更为灵活的“文档”(document)模型。
通过在文档中嵌入文档和数组,面向文档的方法能够仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的看法一致。
另外,不再有预定义模式(predefined schema):文档的键(key)和值(value)不再是固定的类型和大小。由于没有固定的模式,根据需要添加或删除字段变得更容易了。通常由于开发者能够进行快速迭代,所以开发进程得以加快。而且,实验更容易进行。开发者能尝试大量的数据模型,从中选一个最好的。
View Code

2、易扩展性

应用程序数据集的大小正在以不可思议的速度增长。随着可用带宽的增长和存储器价格的下降,即使是一个小规模的应用程序,需要存储的数据量也可能大的惊人,甚至超出
了很多数据库的处理能力。过去非常罕见的T级数据,现在已经是司空见惯了。
由于需要存储的数据量不断增长,开发者面临一个问题:应该如何扩展数据库,分为纵向扩展和横向扩展,纵向扩展是最省力的做法,但缺点是大型机一般都非常贵,而且
当数据量达到机器的物理极限时,花再多的钱也买不到更强的机器了,此时选择横向扩展更为合适,但横向扩展带来的另外一个问题就是需要管理的机器太多。
MongoDB的设计采用横向扩展。面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB能够自动处理跨集群的数据和负载,自动重新分配文档,以及将
用户的请求路由到正确的机器上。这样,开发者能够集中精力编写应用程序,而不需要考虑如何扩展的问题。如果一个集群需要更大的容量,只需要向集群添加新服务器,MongoDB就会自动将现有的数据向新服务器传送
View Code

3、丰富的功能

MongoDB作为一款通用型数据库,除了能够创建、读取、更新和删除数据之外,还提供了一系列不断扩展的独特功能
#1、索引
支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引、全文索引

#2、聚合
支持聚合管道,用户能通过简单的片段创建复杂的集合,并通过数据库自动优化

#3、特殊的集合类型
支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话session。类似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志

#4、文件存储
支持一种非常易用的协议,用于存储大文件和文件元数据。MongoDB并不具备一些在关系型数据库中很普遍的功能,如链接join和复杂的多行事务。省略
这些的功能是处于架构上的考虑,或者说为了得到更好的扩展性,因为在分布式系统中这两个功能难以高效地实现
View Code

4、卓越的性能

MongoDB的一个主要目标是提供卓越的性能,这很大程度上决定了MongoDB的设计。MongoDB把尽可能多的内存用作缓存cache,视图为每次查询自动选择正确的索引。
总之各方面的设计都旨在保持它的高性能
虽然MongoDB非常强大并试图保留关系型数据库的很多特性,但它并不追求具备关系型数据库的所有功能。只要有可能,数据库服务器就会将处理逻辑交给客户端。这种精简方式的设计是MongoDB能够实现如此高性能的原因之一
View Code

二 MongoDB基础知识

1、文档是MongoDB的核心概念。文档就是键值对的一个有序集{\'msg\':\'hello\',\'foo\':3}。类似于python中的有序字典。

需要注意的是:
#1、文档中的键/值对是有序的。
#2、文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
#3、MongoDB区分类型和大小写。
#4、MongoDB的文档不能有重复的键。
#5、文档中的值可以是多种不同的数据类型,也可以是一个完整的内嵌文档。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:
#1、键不能含有\\0 (空字符)。这个字符用来表示键的结尾。
#2、.和$有特别的意义,只有在特定环境下才能使用。
#3、以下划线"_"开头的键是保留的(不是严格要求的)。

 2、集合就是一组文档。如果将MongoDB中的一个文档比喻为关系型数据的一行,那么一个集合就是相当于一张表

#1、集合存在于数据库中,通常情况下为了方便管理,不同格式和类型的数据应该插入到不同的集合,但其实集合没有固定的结构,这意味着我们完全可以把不同格式和类型的数据统统插入一个
集合中。
#2、组织子集合的方式就是使用“.”,分隔不同命名空间的子集合。 比如一个具有博客功能的应用可能包含两个集合,分别是blog.posts和blog.authors,这是为了使组织结构更清晰,这里的blog集合(这个集合甚至不需要存在)跟它的两个子集合没有任何
关系。 在MongoDB中,使用子集合来组织数据非常高效,值得推荐
#3、当第一个文档插入时,集合就会被创建。合法的集合名: 集合名不能是空字符串""。 集合名不能含有\\0字符(空字符),这个字符表示集合名的结尾。 集合名不能以"system."开头,这是为系统集合保留的前缀。 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。

 3、数据库:在MongoDB中,多个文档组成集合,多个集合可以组成数据库

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串:
#1、不能是空字符串("")。
#2、不得含有\' \'(空格)、.、$、/、\\和\\0 (空字符)。
#3、应全部小写。
#4、最多64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
#1、admin: 从身份认证的角度讲,这是“root”数据库,如果将一个用户添加到admin数据库,这个用户将自动获得所有数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库
运行,如列出所有数据库或关闭服务器
#2、local: 这个数据库永远都不可以复制,且一台服务器上的所有本地集合都可以存储在这个数据库中 #3、config: MongoDB用于分片设置时,分片信息会存储在config数据库中

 4、强调:把数据库名添加到集合名前,得到集合的完全限定名,即命名空间

例如:
如果要使用cms数据库中的blog.posts集合,这个集合的命名空间就是
cmd.blog.posts。命名空间的长度不得超过121个字节,且在实际使用中应该小于100个字节

 

 

三 安装

1、 安装

#1、安装路径为D:\\MongoDB,将D:\\MongoDB\\bin目录加入环境变量

#2、新建目录与文件
D:\\MongoDB\\data\\db
D:\\MongoDB\\log\\mongod.log(mongod.log不用创建,制作系统服务时会自动创建)

#3、新建配置文件mongod.cfg,参考: 
https://docs.mongodb.com/manual/reference/configuration-options/
systemLog:
   destination: file
   path: "D:\\MongoDB\\log\\mongod.log"
   logAppend: true
storage:
   journal:
      enabled: true
   dbPath: "D:\\MongoDB\\data\\db"
net:
   bindIp: 0.0.0.0
   port: 27017
setParameter:
   enableLocalhostAuthBypass: false
    
#4、制作系统服务
mongod --config "D:\\MongoDB\\mongod.cfg" --bind_ip 0.0.0.0 --install
或者直接在命令行指定配置 
mongod --bind_ip 0.0.0.0 --port 27017 --logpath D:\\MongoDB\\log\\mongod.log --logappend --dbpath D:\\MongoDB\\data\\db  --serviceName "MongoDB" --serviceDisplayName "MongoDB"  --install  (--auth 重启mdb账户密码时需要加)


#5、启动\\关闭 (在哪启动就在那关)
net start MongoDB
net stop MongoDB

#6、登录
mongo

链接:http://www.runoob.com/mongodb/mongodb-window-install.html

ps:实际操作没做第3步,4步是用下面的方法
安装配置

 2、账号管理

#账号管理:https://docs.mongodb.com/master/tutorial/enable-authentication/
#1、创建账号
use admin
db.createUser(
  {
    user: "root",
    pwd: "123",
    roles: [ { role: "root", db: "admin" } ]
  }
)

use test
db.createUser(
  {
    user: "egon",
    pwd: "123",
    roles: [ { role: "readWrite", db: "test" },
             { role: "read", db: "db1" } ]
  }
)


#2、重启数据库
mongod --remove
mongod --config "C:\\mongodb\\mongod.cfg" --bind_ip 0.0.0.0 --install --auth

#3、登录:注意使用双引号而非单引号
mongo --port 27017 -u "root" -p "123" --authenticationDatabase "admin"

也可以在登录之后用db.auth("账号","密码")登录
mongo
use admin
db.auth("root","123")


ps:重启数据库时采用的是安装时指定配置行加 --auth

#推荐博客:https://www.cnblogs.com/zhoujinyi/p/4610050.html
创建账号密码+开启认证机制

3、命令行shell

#1、mongo 127.0.0.1:27017/config #连接到任何数据库config

#2、mongo --nodb #不连接到任何数据库

#3、启动之后,在需要时运行new Mongo(hostname)命令就可以连接到想要的mongod了:
> conn=new Mongo(\'127.0.0.1:27017\')
connection to 127.0.0.1:27017
> db=conn.getDB(\'admin\')
admin

#4、help查看帮助

#5、mongo时一个简化的javascript shell,是可以执行JavaScript脚本的

ps:以上可以参考 实际未执行
View Code

四 CRUD操作

1、数据库操作

#1、增
use config #如果数据库不存在,则创建数据库,否则切换到指定数据库。

#2、查
show dbs #查看所有
可以看到,我们刚创建的数据库config并不在数据库的列表中, 要显示它,我们需要向config数据库插入一些数据。
db.table1.insert({\'a\':1})

#3、删
use config #先切换到要删的库下
db.dropDatabase() #删除当前库

2、集合操作

#1、增
当第一个文档插入时,集合就会被创建
> use database1
switched to db database1
> db.table1.insert({\'a\':1})
WriteResult({ "nInserted" : 1 })
> db.table2.insert({\'b\':2})
WriteResult({ "nInserted" : 1 })

#2、查
> show tables
table1
table2

#3、删
> db.table1.drop()
true
> show tables
table2

 3、文档操作

增:

#1、没有指定_id则默认ObjectId,_id不能重复,且在插入后不可变

#2、插入单条
user0={
    "name":"egon",
    "age":10,
    \'hobbies\':[\'music\',\'read\',\'dancing\'],
    \'addr\':{
        \'country\':\'China\',
        \'city\':\'BJ\'
    }
}

db.test.insert(user0)
db.test.find()

#3、插入多条
user1={
    "_id":1,
    "name":"alex",
    "age":10,
    \'hobbies\':[\'music\',\'read\',\'dancing\'],
    \'addr\':{
        \'country\':\'China\',
        \'city\':\'weifang\'
    }
}

user2={
    "_id":2,
    "name":"wupeiqi",
    "age":20,
    \'hobbies\':[\'music\',\'read\',\'run\'],
    \'addr\':{
        \'country\':\'China\',
        \'city\':\'hebei\'
    }
}


user3={
    "_id":3,
    "name":"yuanhao",
    "age":30,
    \'hobbies\':[\'music\',\'drink\'],
    \'addr\':{
        \'country\':\'China\',
        \'city\':\'heibei\'
    }
}

user4={
    "_id":4,
    "name":"jingliyang",
    "age":40,
    \'hobbies\':[\'music\',\'read\',\'dancing\',\'tea\'],
    \'addr\':{
        \'country\':\'China\',
        \'city\':\'BJ\'
    }
}

user5={
    "_id":5,
    "name":"jinxin",
    "age":50,
    \'hobbies\':[\'music\',\'read\',],
    \'addr\':{
        \'country\':\'China\',
        \'city\':\'henan\'
    }
}
db.user.insertMany([user1,user2,user3,user4,user5])
单条插入与多条插入

查:

# SQL:=,!=,>,<,>=,<=
# MongoDB:{key:value}代表什么等于什么,"$ne","$gt","$lt","gte","lte",其中"$ne"能用于所有数据类型

#1、select * from db1.user where name = "alex";
db.user.find({\'name\':\'alex\'})

#2、select * from db1.user where name != "alex";
db.user.find({\'name\':{"$ne":\'alex\'}})

#3、select * from db1.user where id > 2;
db.user.find({\'_id\':{\'$gt\':2}})

#4、select * from db1.user where id < 3;
db.user.find({\'_id\':{\'$lt\':3}})

#5、select * from db1.user where id >= 2;
db.user.find({"_id":{"$gte":2,}})

#6、select * from db1.user where id <= 2;
db.user.find({"_id":{"$lte":2}})
比较运算
# SQL:and,or,not
# MongoDB:字典中逗号分隔的多个条件是and关系,"$or"的条件放到[]内,"$not"

#1、select * from db1.user where id >= 2 and id < 4;
db.user.find({\'_id\':{"$gte":2,"$lt":4}})

#2、select * from db1.user where id >= 2 and age < 40;
db.user.find({"_id":{"$gte":2},"age":{"$lt":40}})

#3、select * from db1.user where id >= 5 or name = "alex";
db.user.find({
    "$or":[
        {\'_id\':{"$gte":5}},
        {"name":"alex"}
        ]
})

#4、select * from db1.user where id % 2=1;
db.user.find({\'_id\':{"$mod":[2,1]}})

#5、上题,取反
db.user.find({\'_id\':{"$not":{"$mod":[2,1]}}})
逻辑运算
# SQL:in,not in
# MongoDB:"$in","$nin"

#1、select * from db1.user where age in (20,30,31);
db.user.find({"age":{"$in":[20,30,31]}})

#2、select * from db1.user where name not in (\'alex\',\'yuanhao\');
db.user.find({"name":{"$nin":[\'alex\',\'yuanhao\']}})
成员运算
# SQL: regexp 正则
# MongoDB: /正则表达/i

#1、select * from db1.user where name regexp \'^j.*?(g|n)$\';
db.user.find({\'name\':/^j.*?(g|n)$/i})
正则匹配
#1、select name,age from db1.user where id=3;
db.user.find({\'_id\':3},{\'_id\':0,\'name\':1,\'age\':1})
取指定的字段
#1、查看有dancing爱好的人
db.user.find({\'hobbies\':\'dancing\'})

#2、查看既有dancing爱好又有tea爱好的人
db.user.find({
    \'hobbies\':{
        "$all":[\'dancing\',\'tea\']
        }
})

#3、查看第4个爱好为tea的人
db.user.find({"hobbies.3":\'tea\'})

#4、查看所有人最后两个爱好
db.user.find({},{\'hobbies\':{"$slice":-2},"age":0,"_id":0,"name":0,"addr":0})

#5、查看所有人的第2个到第3个爱好
db.user.find({},{\'hobbies\':{"$slice":[1,2]},"age":0,"_id":0,"name":0,"addr":0})

> db.blog.find().pretty()
{
        "_id" : 1,
        "name" : "alex意外死亡的真相",
        "comments" : [
                {
                        "name" : "egon",
                        "content" : "alex是谁???",
                        "thumb" : 200
                },
                {
                        "name" : "wxx",
                        "content" : "我去,真的假的",
                        "thumb" : 300
                },
                {
                        "name" : "yxx",
                        "content" : "吃喝嫖赌抽,欠下两个亿",
                        "thumb" : 40
                },
                {
                        "name" : "egon",
                        "content" : "xxx",
                        "thumb" : 0
                }
        ]
}
db.blog.find({},{\'comments\':{"$slice":-2}}).pretty() #查询最后两个
db.blog.find({},{\'comments\':{"$slice":[1,2]}}).pretty() #查询1到2
查询数组