百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

MongoDB介绍

itomcoil 2025-02-24 16:48 14 浏览

关系型数据库与非关系型数据库:

MongoDB特性

MongoDB与RDBMS存储结构

MongoDB与RDBMS最大的区别在于: 没有固定的行列组织数据结构

一、MongoDB简介

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

1、易用性

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

2、易扩展性

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

3、丰富的功能

 MongoDB作为一款通用型数据库,除了能够创建、读取、更新和删除数据之外,还提供了一系列不断扩展的独特功能。
 #1、索引
 支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引、全文索引。
 #2、聚合
 支持聚合管道,用户能通过简单的片段创建复杂的集合,并通过数据库自动优化。
 #3、特殊的集合类型
 支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话session。类似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志等...
 #4、文件存储
 支持一种非常易用的协议,用于存储大文件和文件元数据。MongoDB并不具备一些在关系型数据库中很普遍的功能,如链接join和复杂的多行事务。省略这些的功能是处于架构上的考虑,或者说为了得到更好的扩展性,因为在分布式系统中这两个功能难以高效地实现。

4、卓越的性能

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

二、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
#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
#5、启动\关闭
net start MongoDB
net stop MongoDB
#6、登录
mongo
链接:http://www.runoob.com/mongodb/mongodb-window-install.html

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: "tank",
 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")
# 推荐博客:https://www.cnblogs.com/zhoujinyi/p/4610050.html
mongo -u "root" -p "123" --authenticationDatabase "admin"

mysql -u root -p 123

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脚本的
shell命令行

四、基本数据类型

1、在概念上,MongoDB的文档与Javascript的对象相近,因而可以认为它类似于JSON。JSON(http://www.json.org)是一种简单的数据表示方式:其规范仅用一段文字就能描述清楚(其官网证明了这点),且仅包含六种数据类型。

2、这样有很多好处:易于理解、易于解析、易于记忆。然而从另一方面说,因为只有null、布尔、数字、字符串、数字和对象这几种数据类型,所以JSON的表达能力有一定的局限。

3、虽然JSON具备的这些类型已经具有很强的表现力,但绝大数应用(尤其是在于数据库打交道时)都还需要其他一些重要的类型。例如,JSON没有日期类型,这使得原本容易日期处理变得烦人。另外,JSON只有一种数字类型,无法区分浮点数和整数,更别区分32位和64位了。再者JSON无法表示其他一些通用类型,如正则表达式或函数。

4、MongoDB在保留了JSON基本键/值对特性的基础上,添加了其他一些数据类型。在不同的编程语言下,这些类型的确切表示有些许差异。下面说明了MongoDB支持的其他通用类型,以及如何正在文档中使用它们

#1、null:用于表示空或不存在的字段
d={'x':null}
#2、布尔型:true和false
d={'x':true,'y':false}
#3、数值
d={'x':3,'y':3.1415926}
#4、字符串
d={'x':'kermit'}
#5、日期
d={'x':new Date()}
d.x.getHours()
#6、正则表达式
d={'pattern':/^kermit.*?nb$/i}
正则写在//内,后面的i代表:
i 忽略大小写
m 多行匹配模式
x 忽略非转义的空白字符
s 单行匹配模式
#7、数组
d={'x':[1,'a','v']}
#8、内嵌文档
user={'name':'tank','addr':{'country':'China','city':'YT'}}
user.addr.country
#9、对象id:是一个12字节的ID,是文档的唯一标识,不可变
d={'x':ObjectId()}

5、_id 和 ObjectId

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任意类型,默认是个ObjectId对象。
在一个集合里,每个文档都有唯一的“_id”,确保集合里每个文档都能被唯一标识。
不同集合"_id"的值可以重复,但同一集合内"_id"的值必须唯一
#1、ObjectId
ObjectId是"_id"的默认类型。因为设计MongoDb的初衷就是用作分布式数据库,所以能够在分片环境中生成
唯一的标识符非常重要,而常规的做法:在多个服务器上同步自动增加主键既费时又费力,这就是MongoDB采用
ObjectId的原因。
ObjectId采用12字节的存储空间,是一个由24个十六进制数字组成的字符串
 0|1|2|3| 4|5|6| 7|8 9|10|11 
 时间戳 机器 PID 计数器
如果快速创建多个ObjectId,会发现每次只有最后几位有变化。另外,中间的几位数字也会变化(要是在创建过程中停顿几秒)。
这是ObjectId的创建方式导致的,如上图
时间戳单位为秒,与随后5个字节组合起来,提供了秒级的唯一性。这个4个字节隐藏了文档的创建时间,绝大多数驱动程序都会提供
一个方法,用于从ObjectId中获取这些信息。
因为使用的是当前时间,很多用户担心要对服务器进行时钟同步。其实没必要,因为时间戳的实际值并不重要,只要它总是不停增加就好。
接下来3个字节是所在主机的唯一标识符。通常是机器主机名的散列值。这样就可以保证不同主机生成不同的ObjectId,不产生冲突
接下来连个字节确保了在同一台机器上并发的多个进程产生的ObjectId是唯一的
前9个字节确保了同一秒钟不同机器不同进程产生的ObjectId是唯一的。最后3个字节是一个自动增加的 计数器。确保相同进程的同一秒产生的
ObjectId也是不一样的。
#2、自动生成_id
如果插入文档时没有"_id"键,系统会自帮你创建 一个。可以由MongoDb服务器来做这件事。
但通常会在客户端由驱动程序完成。这一做法非常好地体现了MongoDb的哲学:能交给客户端驱动程序来做的事情就不要交给服务器来做。
这种理念背后的原因是:即便是像MongoDB这样扩展性非常好的数据库,扩展应用层也要比扩展数据库层容易的多。将工作交给客户端做就
减轻了数据库扩展的负担。

五 CRUD操作 (create、read、update、delete)

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":"tank",
 "age":10,
 'hobbies':['music','read','dancing'],
 'addr':{
 'country':'China',
 'city':'GD'
 }
}
db.test.insert(user0)
db.test.find()
#3、插入多条
user1={
 "_id":1,
 "name":"tank",
 "age":10,
 'hobbies':['music','read','dancing'],
 'addr':{
 'country':'China',
 'city':'GuangZhou'
 }
}
user2={
 "_id":2,
 "name":"egon",
 "age":20,
 'hobbies':['music','read','run'],
 'addr':{
 'country':'China',
 'city':'ShanDong'
 }
}
user3={
 "_id":3,
 "name":"jason",
 "age":30,
 'hobbies':['music','drink'],
 'addr':{
 'country':'China',
 'city':'AnHui'
 }
}
user4={
 "_id":4,
 "name":"kevin",
 "age":40,
 'hobbies':['music','read','dancing','tea'],
 'addr':{
 'country':'China',
 'city':'ShanDong'
 }
}
user5={
 "_id":5,
 "name":"nick",
 "age":50,
 'hobbies':['music','read',],
 'addr':{
 'country':'China',
 'city':'SH'
 }
}
db.user.insertMany([user1,user2,user3,user4,user5])

# 比较运算符
# SQL:=,!=,>,<,>=,<=
# MongoDB:{key:value}代表什么等于什么,"$ne","$gt","$lt","gte","lte",其中"$ne"能用于所有数据类型
# 1.select * from db1.user where id = 1;
# 2.select * from db1.user where id != 1;
# 3.select * from db1.user where id > 2;
# 4.select * from db1.user where age < 30;
# 5.select * from db1.user where id >= 2;
# 6.select * from db1.user where id <= 5;
# 逻辑运算符
 $and, $or, $not
# 1.$and
mysql:
select * from db1.user where id >= 3 and id <= 4;
select * from db1.user where id >=3 and id <=4 and age > 20;
# 先获取条件内有的, 然后通过$and来进行判断
select * from db1.user where id >=2 and id <=5 and age > 30; 
# 2.$or
select * from db1.user where id >=0 and id <=1 or id >= 4 or name = "egon";
# 3.$mod
select * from db1.user where id % 2 =1;
# 4.not
db.user.find({"_id":{
		"$not": {"$mod":[2, 1]}
		}})
 # 成员运算
 $in $nin
     有egon与kevin名字的
 
     没有tank名字的
 # 正则匹配
 select * from db1.user where name regexp "^ke.*?(g|n)$";
 > db.user.find({"name": /^ke.*?(g|n)$/i)
 
 
 
 # 查看指定字段 1代表True 0代表False
 select name, age from db1.user where name regexp "^ke.*?(n|g)$";
 db.user.find(
 {
 "name": /^ke.*?(g|n)$/i
 },
 {
 "_id": 0,
 "name": 1,
 "age":1
 }
 )
 
 
 # 查询数组相关的
 # 查找音乐爱好的选手
 db.user.find({
 "hobbies": "music" 
 })
 
 # 我要写多个爱好,有好多,写到哪里去
 # 是不是写到数组里面去,查找既有音乐又有篮球的选手
 db.user.find({
 "hobbies":{"$all":["music", "basketball"]}
 })
 
 # 查找第二个爱好是篮球的
 db.user.find({"hobbies.1": "basketball"})
# 来,你给我找出所有人的后两个爱好
 db.user.find(
 {},
 {
 "_id": 0,
 "name": 0,
 "age": 0,
 "addr": 0,
 # "hobbies": 1
 "hobbies": {"$slice": -2}
 }
 ) 
 
 # 查找第一和第二个爱好
 db.user.find(
 {},
 {
 "_id": 0,
 "name": 0,
 "age": 0,
 "addr": 0,
 "hobbies": {"$slice": [0, 2]}
 }
 ) 
 
 # 补充: addr.
 # 针对查找内嵌文档的方式 
 # 我要找到addr下面city为hebei的
 db.user.find({"addr.city": "guangzhou"})
 
 
 
 # 排序
 # 升序 sort()
 db.user.find().sort({"_id": 1})
 # 降序
 db.user.find().sort({"_id": -1})
 db.user.find().sort({"_id": 1, "age": -1}})
 
 
 # 分页查询 limit()
 # 分页两条
 db.user.find().limit(2)
 # 从第0页开始分页
 db.user.find().limit(2).skip(0)
 # 从第2页开始分页
 db.user.find().limit(2).skip(2)
 # 从第4页开始分页
 db.user.find().limit(2).skip(4)
 
 
 # 查找数量
 db.user.count()
 
 # 杂项目
 db.t2.insert({"a": 10, "b":5})
 db.t2.insert({"a": 10, "b":null})
 db.t2.insert({"a": 10}) 
 
 # 查看key为b的和b的值为null的
 db.t2.find({"b":null})
 { "_id":ObjectId("5c4888c5ce1c93e5aba5b2b3"),"a":10,"b":null}
 { "_id" : ObjectId("5c4888c7ce1c93e5aba5b2b4"), "a" : 10 }

相关推荐

selenium(WEB自动化工具)

定义解释Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8,9,10,11),MozillaF...

开发利器丨如何使用ELK设计微服务中的日志收集方案?

【摘要】微服务各个组件的相关实践会涉及到工具,本文将会介绍微服务日常开发的一些利器,这些工具帮助我们构建更加健壮的微服务系统,并帮助排查解决微服务系统中的问题与性能瓶颈等。我们将重点介绍微服务架构中...

高并发系统设计:应对每秒数万QPS的架构策略

当面试官问及"如何应对每秒几万QPS(QueriesPerSecond)"时,大概率是想知道你对高并发系统设计的理解有多少。本文将深入探讨从基础设施到应用层面的解决方案。01、理解...

2025 年每个 JavaScript 开发者都应该了解的功能

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.Iteratorhelpers开发者...

JavaScript Array 对象

Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...

Gemini 2.5编程全球霸榜,谷歌重回AI王座,神秘模型曝光,奥特曼迎战

刚刚,Gemini2.5Pro编程登顶,6美元性价比碾压Claude3.7Sonnet。不仅如此,谷歌还暗藏着更强的编程模型Dragontail,这次是要彻底翻盘了。谷歌,彻底打了一场漂亮的翻...

动力节点最新JavaScript教程(高级篇),深入学习JavaScript

JavaScript是一种运行在浏览器中的解释型编程语言,它的解释器被称为JavaScript引擎,是浏览器的一部分,JavaScript广泛用于浏览器客户端编程,通常JavaScript脚本是通过嵌...

一文看懂Kiro,其 Spec工作流秒杀Cursor,可移植至Claude Code

当Cursor的“即兴编程”开始拖累项目质量,AWS新晋IDEKiro以Spec工作流打出“先规范后编码”的系统工程思维:需求-设计-任务三件套一次生成,文档与代码同步落地,复杂项目不...

「晚安·好梦」努力只能及格,拼命才能优秀

欢迎光临,浏览之前点击上面的音乐放松一下心情吧!喜欢的话给小编一个关注呀!Effortscanonlypass,anddesperatelycanbeexcellent.努力只能及格...

JavaScript 中 some 与 every 方法的区别是什么?

大家好,很高兴又见面了,我是姜茶的编程笔记,我们一起学习前端相关领域技术,共同进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力在JavaScript中,Array.protot...

10个高效的Python爬虫框架,你用过几个?

小型爬虫需求,requests库+bs4库就能解决;大型爬虫数据,尤其涉及异步抓取、内容管理及后续扩展等功能时,就需要用到爬虫框架了。下面介绍了10个爬虫框架,大家可以学习使用!1.Scrapysc...

12个高效的Python爬虫框架,你用过几个?

实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫,为什么呢?因为Python确实很适合做爬虫,丰富的第三方库十分强大,简单几行代码便可实...

pip3 install pyspider报错问题解决

运行如下命令报错:>>>pip3installpyspider观察上面的报错问题,需要安装pycurl。是到这个网址:http://www.lfd.uci.edu/~gohlke...

PySpider框架的使用

PysiderPysider是一个国人用Python编写的、带有强大的WebUI的网络爬虫系统,它支持多种数据库、任务监控、项目管理、结果查看、URL去重等强大的功能。安装pip3inst...

「机器学习」神经网络的激活函数、并通过python实现激活函数

神经网络的激活函数、并通过python实现whatis激活函数感知机的网络结构如下:左图中,偏置b没有被画出来,如果要表示出b,可以像右图那样做。用数学式来表示感知机:上面这个数学式子可以被改写:...