笔记整理——MongoDB基础篇

110 阅读2分钟

MongoDB

简介

MongoDB 有哪些特点

● 文档型数据库 ● 高性能 ● 灵活性 ● 可扩展性 ● 强大的查询语言 ● 优异的性能 ● 高性能:支持使用嵌入数据时,减少系统I/O负担,支持子文档查询 ● 多种查询类型支持,且支持数据聚合查询、文本检索、地址位置查询 ● 高可用、水平扩展:支持副本集与分片 ● 多种存储引擎:WiredTiger , In-Memory MongoDB 适用于哪些场景

1、需要处理大量的低价值数据,且对数据处理性能有较高要求

比如,对微博数据的处理就不需要太高的事务性,但是对数据的存取性能有很高的要求,这时就非常适合使用 MongoDB。

2、需要借助缓存层来处理数据

因为 MongoDB 能高效的处理数据,所以非常适合作为缓存层来使用。将 MongoDB 作为持久化缓存层,可以避免底层存储的资源过载。

3、需要高度的伸缩性

对关系型数据库而言,当表的大小达到一定数量级后,其性能会急剧下降。这时可以使用多台 MongoDB 服务器搭建一个集群环境,实现最大程度的扩展,且不影响性能。

安装 MongoDB

1.在 macOS 中安装 MongoDB

使用 homebrew 安装 MongoDB
  1. 安装 Command Line Tools for Xcode 如果你电脑上安装了 XCode 软件开发工具(在App Store中安装Xcode),Command Line Tools for Xcode已经给你安装好了。 也可以直接安装 Command Line Tools for Xcode。在终端输入以下代码完成安装:
    xcode-select --install
    
  2. 安装 Homebrew
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
    
  3. 添加 MongoDB 安装源到 Homebrew
    brew tap mongodb/brew
    
  4. 使用 homebrew 安装 MongoDB
    brew install mongodb-community@4.4
    

该安装除安装必要的二进制文件之外,还会创建运行 MongoDB 服务所需的文件目录:

  • MongoDB 配置文件:/usr/local/etc/mongod.conf
  • 日志文件存储目录:/usr/local/var/log/mongodb
  • 数据文件存储目录:/usr/local/var/mongodb
管理 MongoDB 服务
启动 MongoDB

启动 MongoDB 并运行在后台。 shell brew services start mongodb-community@4.4 或者手动启动 MongoDB,运行在前台。也可以加入 --fork 参数运行在后台。 shell mongod --config /usr/local/etc/mongod.conf

查看 MongoDB 服务运行状态

要验证MongoDB是否正在运行,请在正在运行的进程中搜索 mongod: shell ps aux | grep -v grep | grep mongod 还可以通过查看日志文件以查看 mongod 进程的当前状态:/usr/local/var/log/mongodb/mongo.log

停止 MongoDB
brew services stop mongodb-community@4.4
卸载 MongoDB
brew uninstall mongodb-community@4.4

2.在 Windows 中安装 MongoDB

这里以 Windows 手动安装 MongoDB 为例。 1、下载 MongoDB 安装包 www.mongodb.com/try/downloa…

2、解压压缩包,将解压出来的资源文件放到一个稳定的目录中

3、关于 MongoDB 软件包目录文件

文件名说明
mongod.exe服务端,用来启动数据库服务的
mongo.exe客户端,用来连接数据库服务操作数据库

4、将 MongoDB 安装包中的 bin 目录配置到环境 PATH 变量配置 PATH 环境变量的目的是为了能够在命令行中的任何位置都能够访问到 bin 目录中的可执行程序。

1.png

C:\Users\HMSJ1\mongodb-win32-x86_64-windows-4.4.18\bin

5、确认是否配置成功() mongod --version

注意:如果是配置环境变量之前打开的命令行,则需要在配置完环境变量之后将命令行重启才能生效。

启动和停止 MongoDB 数据库服务

mongod --dbpath="数据存储目录"

mongod 默认监听 127.0.0.1:27017。
如果单独执行 mongod,它会默认使用执行 mongod 命令所处磁盘根目录/data/db 作为数据存储目录。

2.png

正确的操作流程:

  • 在本地目录中新增一个data目录
  • 复制data目录的完整路径"C:\Users\HMSJ1\mongodb-win32-x86_64-windows-4.4.18\data"
  • 启动命令行输入mongod --dbpath="C:\Users\HMSJ1\mongodb-win32-x86_64-windows-4.4.18\data"

3.png

启动 mongo Shell 并连接到 MongoDB

连接默认端口上的本地 MongoDB 服务

不能关闭已经启动的mongod

您可以在没有任何命令行选项的情况下运行 mongo shell,以使用默认端口 27017 连接到在本地主机上运行的 MongoDB 实例

mongo

连接非默认端口上的本地 MongoDB 服务

要明确指定端口,请包括 --port 命令行选项。例如,要使用非默认端口 28015 连接到在 localhost 上运行的 MongoDB 实例,请执行以下操作:

mongo --port 28015

连接远程主机上的 MongoDB 服务

连接远程主机上的 MongoDB 服务需要明确指定主机名和端口号。 您可以指定一个连接字符串。例如,要连接到在远程主机上运行的 MongoDB 实例,请执行以下操作

mongo "mongodb://mongodb0.example.com:28015"

您可以使用命令行选项 --host <主机>:<端口>。例如,要连接到在远程主机上运行的 MongoDB 实例,请执行以下操作:

mongo --host mongodb0.example.com --port 28015

连接具有身份认证的 MongoDB 服务

您可以在连接字符串中指定用户名,身份验证数据库以及可选的密码。例如,以alice用户身份连接并认证到远程MongoDB实例:

mongo "mongodb://alice@mongodb0.examples.com:28015/?authSource=admin"

注意:如果您指定--password而不输入用户密码,则外壳程序将提示您输入密码

MongoDB基本操作

存储结构:数据库——>集合——>文档
MongoDB 将数据记录存储为 BSON 文档,BSON(Binary JSON)是 JSON 文档的二进制表示形式,它比 JSON 包含更多的数据类型

数据库

数据库名称规则
  • 不区分大小写,但是建议全部小写
  • 不能包含空字符。
  • 数据库名称不能为空,并且必须少于64个字符。
  • Windows 上的命名限制
    • 不能包括 /. "$*<>:|? 中的任何内容
  • Unix 和 Linux 上的命名限制
    • 不能包括 /. "$ 中的任何字符
数据库操作
show dbs //查看数据库列表
db //查看当前数据库
use <数据库名称> // use test  创建或切换数据库
db.dropDatabase() //删除当前数据库

集合

集合名称规则

集合名称应以下划线或字母字符开头,并且:

  • 不能包含 $
  • 不能为空字符串
  • 不能包含空字符
  • 不能以 . 开头
  • 长度限制
    • 版本 4.2 最大 120 个字节
    • 版本 4.4 最大 255 个字节
集合操作
db.test.insert({name:1}) //创建test集合并在集合中写入数据
db.createCollection()//方法来显式创建具有各种选项的集合,例如设置最大大小或文档验证规则
show collections //查看集合
db.集合名称.drop() //删除集合 db.test.drop()

文档

文档名称规则

文档对字段名称有以下限制:

  • 字段名称 _id 保留用作主键;它的值在集合中必须是唯一的,不可变的,并且可以是数组以外的任何类型。
  • 字段名称不能包含空字符。
  • 顶级字段名称不能以美元符号 $ 开头。
    • 从 MongoDB 3.6 开始,服务器允许存储包含点 . 和美元符号 $ 的字段名称
常用的数据类型
类型整数标识符别名(字符串标识符)描述
Double1“double”双精度浮点值。用于存储浮点值。
String2“string”字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Object3“object”用于内嵌文档
Array4“array”用于将数组或列表或多个值存储为一个键。
Binary data5“binData”二进制数据。用于存储二进制数据。
ObjectId7“objectId”对象 ID。用于创建文档的 ID。
Boolean8“bool”布尔值。用于存储布尔值(真/假)。
Date9“date”日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Null10“null”用于创建空值。
Regular Expression11“regex”正则表达式类型。用于存储正则表达式。
32-bit integer16“int”整型数值。用于存储 32 位整型数值。
Timestamp17“timestamp”时间戳。记录文档修改或添加的具体时间。
64-bit integer18“long”整型数值。用于存储 64 位整型数值。
Decimal12819“decimal”数值类型。常用于存储更精确的数字,例如货币。
文档操作(CRUD)
1. 创建文档(create)
方法描述
db.collection.insertOne()插入单个文档到集合中
db.collection.insertMany()插入多个文档到集合中
db.collection.insert()将1个或多个文档插入到集合中
// 插入单个文档
db.inventory.insertOne(
   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
// 插入多个文档
db.inventory.insertMany([
   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
// 插入1个或多个文档
db.inventory.insert( { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } })
db.inventory.insert([
   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
2. 查询文档(read)
方法描述
db.collection.find(query, projection)query :可选,使用查询操作符指定查询条件;projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)
db.collection.findOne()单个查询
基础查询
  • 查询所有文档
    // 查询所有文档
    db.inventory.find( {} ) //等价于 SQL 中的 SELECT * FROM inventory 语句
    db.inventory.find().pretty() //格式化打印结果
    
  • 相同条件查询
    db.inventory.find( { status: "D" } ) //等价于 SQL 中的 SELECT * FROM inventory WHERE status = "D" 语句
    
  • 多个查询条件同时满足(AND条件)
    //检索状态为“ A”且数量小于($ lt)30的清单集合中的所有文档
    db.inventory.find( { status: "A", qty: { $lt: 30 } } ) //等价于 SQL 中的 SELECT * FROM inventory WHERE status = "A" AND qty < 30
    
  • 满足其中一个查询条件(OR条件)
    //检索状态为 A 或数量小于 $lt30 的集合中的所有文档
    db.inventory.find({
        $or: [
            { status: "A" },
            { qty: { $lt: 30 } }
        ]
    })//等价于 SQL 中的SELECT * FROM inventory WHERE status = "A" OR qty < 30
    
  • 指定 AND 和 OR 条件
    //检索状态为“ A”且qty小于($ lt)30或item以字符p开头的所有文档
    db.inventory.find({
        status: "A",
        $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]
    }) //等价于 SQL 中的SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")
    
  • 查询运算符指定条件
    //检索状态为“ A”或“ D”所有文档
    db.inventory.find( { status: { $in: [ "A", "D" ] } } )//等价于 SQL 中的SELECT * FROM inventory WHERE status in ("A", "D")
    
  • 查询运算符
    • 比较运算符

      名称描述
      $eq匹配等于指定值的值。
      $gt匹配大于指定值的值
      $gte匹配大于或等于指定值的值
      $in匹配数组中指定的任何值
      $lt匹配小于指定值的值
      $lte匹配小于或等于指定值的值
      $ne匹配所有不等于指定值的值
      $nin不匹配数组中指定的任何值
    • 逻辑运算符

      名称描述
      $and将查询子句与逻辑连接,并返回与这两个子句条件匹配的所有文档
      $not反转查询表达式的效果,并返回与查询表达式不匹配的文档
      $nor用逻辑NOR连接查询子句,返回所有不能匹配这两个子句的文档
      $or用逻辑连接查询子句,或返回与任一子句条件匹配的所有文档。
查询嵌套文档
  • 匹配嵌套文档(完全匹配包括字段顺序)
    //查询选择字段大小等于文档 {h: 14, w: 21, uom: "cm"} 的所有文档
    db.inventory.find({
        size: { h: 14, w: 21, uom: "cm" }
    }) //整个嵌入式文档上的相等匹配要求与指定的 <value> 文档完全匹配,包括字段顺序
    
  • 查询嵌套字段(使用点符号查询时,字段和嵌套字段必须在引号内)
    • 在嵌套字段上指定相等匹配
      //查询嵌套在 size 字段中的 uom 字段等于 "in"  的所有文档
      db.inventory.find({
          "size.uom": "in"
      })
      
    • 使用查询运算符指定匹配项
      //查询在 size 字段中嵌入的字段 h 上使用小于运算符 $lt
      db.inventory.find({
          "size.h": { $lt: 15 }
      })
      //查询选择嵌套字段 h 小于 15,嵌套字段 uom 等于 "in",状态字段等于 "D" 的所有文档
      db.inventory.find({
          "size.h": { $lt: 15 },
          "size.uom": "in",
          status: "D"
      })
      
  • 查询数组
    • 匹配一个数组(匹配的精确数组,包括元素的顺序) $all 可以不考虑顺序或该数组中的其他元素
      //按指定顺序恰好具有两个元素 "red" 和 "blank" 的数组
      db.inventory.find({
          tags: ["red", "blank"]
      })
      //找到一个同时包含元素 "red" 和 "blank" 的数组,而不考虑顺序或该数组中的其他元素,请使用 $all 运算符
      db.inventory.find({
          tags: { $all: ["red", "blank"] }
      })
      
    • 查询数组中的元素
      //查询tags数组字段是否包含至一个具有指定值的元素
      db.inventory.find({
          tags: "red"
      })
      //查询数组 dim_cm 包含至少一个值大于 25 的元素的所有文档
      db.inventory.find({
          dim_cm: { $gt: 25 }
      })
      
    • 为数组元素指定多个条件 在数组元素上指定复合条件时,可以指定查询,以使单个数组元素满足这些条件,或者数组元素的任何组合均满足条件。
      1. 使用数组元素上的复合过滤条件查询数组
        //一个元素可以满足大于 15 的条件,而另一个元素可以满足小于 20 的条件;或者单个元素可以满足以下两个条件
        db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } )
        
      2. 查询满足多个条件的数组元素 使用 $elemMatch 运算符可以在数组的元素上指定多个条件,以使至少一个数组元素满足所有指定的条件
        //查询在 dim_cm 数组中包含至少一个同时 大于22  和 小于30 的元素的文档
        db.inventory.find({
            dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } }
        })
        
      3. 通过数组索引位置查询元素 使用点符号,可以为数组的特定索引或位置指定元素的查询条件。该数组使用基于零的索引(注意:使用点符号查询时,字段和嵌套字段必须在引号内)
        //查询数组 dim_cm 中第二个元素大于 25 的所有文档
        db.inventory.find( { "dim_cm.1": { $gt: 25 } } )
        
      4. 通过数组长度查询数组 使用 $size 运算符可按元素数量查询数组
        //查询数组标签具有3个元素的文档
        db.inventory.find( { "tags": { $size: 3 } } )
        
  • 查询嵌入文档的数组
    db.inventory.insertMany( [
        { item: "journal", instock: [ { warehouse: "A", qty: 5 }, { warehouse: "C", qty: 15 } ] },
        { item: "notebook", instock: [ { warehouse: "C", qty: 5 } ] },
        { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 15 } ] },
        { item: "planner", instock: [ { warehouse: "A", qty: 40 }, { warehouse: "B", qty: 5 } ] },
        { item: "postcard", instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] }
    ]);
    
    • 查询嵌套在数组中的文档 整个嵌入式/嵌套文档上的相等匹配要求与指定文档(包括字段顺序)完全匹配
      //
      db.inventory.find({
          "instock": { warehouse: "A", qty: 5 }
      })
      
    • 在文档数组中的字段上指定查询条件
      1. 在嵌入文档数组中的字段上指定查询条件 如果您不知道嵌套在数组中的文档的索引位置,请使用点(。)和嵌套文档中的字段名称来连接数组字段的名称
        //数组中包含至少一个嵌入式文档的嵌入式文档,这些嵌入式文档包含值小于或等于20的字段qty
        db.inventory.find( { 'instock.qty': { $lte: 20 } } )
        
      2. 使用数组索引在嵌入式文档中查询字段 使用点表示法,您可以为文档中特定索引或数组位置处的字段指定查询条件。该数组使用基于零的索引(注意:使用点符号查询时,字段和索引必须在引号内。)
        //数组的第一个元素是包含值小于或等于20的字段qty的文档
        db.inventory.find( { 'instock.0.qty': { $lte: 20 } } )
        
    • 为文档数组指定多个条件 在嵌套在文档数组中的多个字段上指定条件时,可以指定查询,以使单个文档满足这些条件,或者数组中文档的任何组合(包括单个文档)都满足条件
      1. 单个嵌套文档在嵌套字段上满足多个查询条件 使用$ elemMatch运算符可在一组嵌入式文档上指定多个条件,以使至少一个嵌入式文档满足所有指定条件
        //查询数组中至少有一个嵌入式文档的文档,这些文档同时包含等于5的字段qty和等于A的字段仓库
        db.inventory.find( { "instock": { $elemMatch: { qty: 5, warehouse: "A" } } } )
        //查询数组中至少有一个嵌入式文档的嵌入式文档包含的字段qty大于10且小于或等于20
        db.inventory.find( { "instock": { $elemMatch: { qty: { $gt: 10, $lte: 20 } } } } )
        
      2. 元素组合满足标准 如果数组字段上的复合查询条件未使用$ elemMatch运算符,则查询将选择其数组包含满足条件的元素的任意组合的那些文档。
        //查询匹配文档,其中嵌套在库存数组中的任何文档的qty字段都大于10,而数组中的任何文档(但不一定是同一嵌入式文档)的qty字段小于或等于20
        db.inventory.find( { "instock.qty": { $gt: 10,  $lte: 20 } } )
        //查询数组中具有至少一个包含数量等于5的嵌入式文档和至少一个包含等于A的字段仓库的嵌入式文档(但不一定是同一嵌入式文档)的文档
        db.inventory.find( { "instock.qty": 5, "instock.warehouse": "A" } )
        
指定从查询返回的项目字段
  • 返回匹配文档中所有字段
    //返回状态为 "A" 的清单集合中所有文档的所有字段
    db.inventory.find( { status: "A" } )
    
  • 仅返回指定字段和 _id 字段 find方法中的第二个参数可以指定返回项目数据
    //匹配的文档中仅返回项目,状态和默认情况下的 _id 字段
    db.inventory.find( { status: "A" }, { item: 1, status: 1 } )
    
  • 禁止 _id 字段
    //通过将投影中的 _id 字段设置为 0 来从结果中删除 _id 字段
    db.inventory.find( { status: "A" }, { item: 1, status: 1, _id: 0 } )
    
  • 返回所有但排除的字段
    //
    db.inventory.find( { status: "A" }, { status: 0, instock: 0 } )
    
  • 返回嵌入式文档中的特定字段 使用点表示法引用嵌入式字段,并在投影文档中将其设置为1
    db.inventory.find(
        { status: "A" },
        { item: 1, status: 1, "size.uom": 1 }
    )
    // 从MongoDB 4.4 开始,您还可以使用嵌套形式指定嵌入式字段,例如 {item: 1, status: 1, size: {uom: 1}}
    
  • 禁止嵌入文档中的特定字段 使用点表示法引用投影文档中的嵌入字段并将其设置为0
    db.inventory.find(
        { status: "A" },
        { "size.uom": 0 }
    )
    //从 MongoDB 4.4 开始,您还可以使用嵌套形式指定嵌入式字段,例如 { size: { uom: 0 } }
    
  • 在数组中的嵌入式文档上投射 使用点表示法可将特定字段投影在嵌入数组的文档中
    db.inventory.find( { status: "A" }, { item: 1, status: 1, "instock.qty": 1 } )
    
  • 返回数组中的项目特定数组元素 含数组的字段,MongoDB 提供以下用于操纵数组的投影运算符:$elemMatch,$slice 和$
    // $slice 投影运算符返回库存数组中的最后一个元素
    db.inventory.find( { status: "A" }, { item: 1, status: 1, instock: { $slice: -1 } } )
    

    $elemMatch,$slice 和 $ 是投影要包含在返回数组中的特定元素的唯一方法。例如,您不能使用数组索引来投影特定的数组元素。例如{“ instock.0”:1}投影不会投影第一个元素的数组

指定从查询返回的项目字段

MongoDB 中的不同查询运算符对空值的处理方式不同 js db.inventory.insertMany([ { _id: 1, item: null }, { _id: 2 } ])

  • 相等过滤器
    //{item: null} 查询将匹配包含其值为 null 的 item 字段或不包含 item 字段的文档
    db.inventory.find( { item: null } )
    //该查询返回集合中的两个文档
    
  • 类型检查 { item: { $type: 10 } } 查询仅匹配包含 item 字段,其值为 null 的文档;即 item 字段的值为 BSON 类型为 Null(类型编号10):
    //仅返回 item 字段值为 null 的文档
    db.inventory.find( { item : { $type: 10 } } )
    
  • 存在检查
    //仅返回不包含 item 字段的文档
    db.inventory.find( { item : { $exists: false } } )
    
3. 更新文档(update)
方法描述
db.collection.updateOne(<filter>, <update>, <options>)更新单个
db.collection.updateMany(<filter>, <update>, <options>)更新多个
db.collection.replaceOne(<filter>, <update>, <options>)替换单个

参数解释:

  • filter:筛选条件,使用相同于find()方法中query参数
  • update:更新的数据
  • options:选项

参数详情

// 更新单个文档
db.inventory.updateOne(
   { item: "paper" },
   {
     $set: { "size.uom": "cm", status: "P" },
     $currentDate: { lastModified: true }
   }
)
// 更新多个文档
db.inventory.updateMany(
   { "qty": { $lt: 50 } },
   {
     $set: { "size.uom": "in", status: "P" },
     $currentDate: { lastModified: true }
   }
)
// 更新操作:

//  使用 $set 运算符将 size.uom 字段的值更新为 "in",将状态字段的值更新为 "p"
//  使用 $currentDate 运算符将 lastModified 字段的值更新为当前日期。如果 lastModified 字段不存在,则 $currentDate 将创建该字段


// 替换文档
db.inventory.replaceOne(
   { item: "paper" },
   { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)  //要替换 _id 字段以外的文档的全部内容
4. 删除文档(delete)
方法描述
db.collection.deleteMany(<filter>,<options>)删除多个
db.collection.deleteOne(<filter>,<options>)删除单个
参数解释:
  • filter:筛选条件,使用相同于find()方法中query参数
  • options:选项

参数详情

// 删除所有文档
db.inventory.deleteMany({})
// 删除所有符合条件的文档
db.inventory.deleteMany({ status : "A" }) //删除inventory集合中状态字段等于“ A”的所有文档
// 删除1个符合条件的文档
db.inventory.deleteOne( { status: "D" } ) //删除状态为“ D”的第一个文档