# 管理单元

MongoDB 的管理单元从上到下依次分为:

  • database
    • :数据库,相当于 MySQL 的数据库。
    • 一个 MongoDB 服务器中可以存储多个 database 。
  • collection
    • :集合,相当于 MySQL 的数据表。
    • 每个 database 中可以存储多个 collection 。
  • document
    • :文档,相当于 MySQL 的数据行。
    • 每个 collection 中可以存储多个 document 。

# database

MongoDB 中默认有三个数据库。

  • admin :保存用户的信息。
  • local :该数据库不会被复制,常用于保存一些仅限本机使用的集合。
  • config :保存配置信息。

#

show dbs           // 显示所有数据库的名字、占用磁盘
use db1            // 切换到指定数据库
db                 // 显示当前数据库的名字

db.stats()         // 显示当前数据库的状态信息
db.getMongo()      // 显示当前数据库存储在哪个主机上
db.getSiblingDB('db1').stats()  // 根据名称获得一个数据库对象的引用
  • MongoDB 没有提供数据库的 create 命令。但可以用 use 命令切换到一个不存在的数据库,进行写操作时会自动创建它。
  • 通过 db.runCommand(...) 可执行一些非 CRUD 类型的数据库命令,此时会与一个内置的虚拟集合 $cmd 交互。

#

db.dropDatabase()  // 删除当前数据库

# collection

#

show collections        // 显示当前数据库的所有集合,也可执行 show tables

db.c1                   // 通过数据库成员的方式获得指定集合的引用,此时集合名必须遵循 C 语言命名风格
db.getCollection('c1')  // 根据名称获得一个集合的引用

db.<collection>.stats()       // 显示指定集合的状态信息
db.<collection>.stats().count // 集合中的文档数,不包括已标记为 deleted 的文档
  • 例:遍历所有数据库的所有集合
    db.adminCommand("listDatabases").databases.forEach(function(d){
        db = db.getSiblingDB(d.name);
        cols = db.getCollectionNames();
        cols.forEach(function(col){
            print(col, db.getCollection(col).stats().size);
        });
    });
    

#

db.createCollection('c1')   // 创建集合
db.createCollection('c1', {max:1000})
db.createCollection('c1', {capped:true, size:10000})
  • max :可选参数,表示集合中最多可以包含的文档数量,单位为个。
    • 当集合满了时(达到 max 或 size),新插入的文档会从集合头部开始存储,覆盖旧文档。
  • capped、size :一对搭配使用的可选参数,表示创建固定大小的集合,单位为 KB 。
    • 固定集合的插入、查询速度很快,还会记住每个文档的插入顺序,但是不能删除其中的文档,只能删除整个集合。

#

db.getCollection('c1').renameCollection('c2');    // 重命名集合

#

db.<collection>.drop()    // 删除集合

# document

文档采用 BSON 格式存储数据,特点如下:

  • 与 JSON 的语法类似。
  • 以二进制形式存储数据。
  • BSON 中的键值对是有序存储的,区分大小写。
  • key 只能是 String 类型,取值不能重复。
    • 以下划线 _ 开头的 key 是保留的,用户不应该使用。
  • value 可以是以下类型:
    • 与 JSON 相似的数据类型:
      • null
      • Number
      • Boolean
      • String(采用 utf-8 编码)
      • Array
      • Object(嵌套另一个文档)
    • ObjectId :文档 ID
      • 占 12 bytes ,是每个文档的唯一标识符。
      • 例如 62a03eb3ec744e00015b1f26 ,用 4 bytes 存储创建该文档的时间戳,用 3 bytes 存储该主机的 ID ,用 2 bytes 存储进程的 PID ,最后 3 bytes 是随机数。
    • Timestamp :时间戳
      • 占 8 bytes 。前 4 bytes 是 UTC 时间戳(精确到秒),后 4 bytes 是在该秒中的操作序号。
      • 主要被 MongoDB 内部使用。
    • Date :日期
      • 精确到毫秒,可以用 Date() 函数获取。

#

db.<collection>.find([query], [projection])      // 返回所有匹配的文档
db.<collection>.findOne([query], [projection])   // 返回第一个匹配的文档
  • query 参数表示查询条件,相当于 MySQL 的 where 子句。

    • 如果 query 参数为空或 { } ,则匹配所有文档。
    • 例:
      {"_id": ObjectId("62a03eb3ec744e00015b1f26")}           // 查询字段 _id 等于指定值的文档
      {"_id": {"$eq": {"$oid": "62a03eb3ec744e00015b1f26"}}}  // ObjectId() 函数只能在 Mongo Shell 中执行,在 JSON 中需要使用 $oid 的格式,比如显示慢日志时会自动转换成 $oid
      {"name": "leo"}
      {"student.id": 1}               // 可以选择子字段
      {"students.1.id": 1}            // 这里 students 是 array 类型,选取其中第 1 个元素的 id 字段
      {"name": {"$type":"string"}}    // 字段 name 为 string 类型
      {"age": {"$gt":0, "$lt":10}}    // 字段 age 大于 0、小于 10
      {"age": {"$gte":0, "$lte":10}}  // 字段 age 大于等于 0、小于等于 10
      {"age": {"$in":(10,11,12)}      // 字段 age 使用指定的某个值
      {"tags": {"$all":[1,2,3]}}      // 字段 tags 是 array 类型,且包含指定的所有值
      
    • 查询某个 ObjectId 所属的时刻:
      ObjectId("62a03eb3ec744e00015b1f26").getTimestamp()
      
    • 查询在指定时刻之后创建的文档:
      id1 = Math.floor((new ISODate('2022-01-01T00:00:00+08:00'))/1000).toString(16) + '0000000000000000';
      db.getCollection('test').find({_id:{$gte: ObjectId(id1)}}).count();
      
  • projection 参数用于筛选 query 的查询结果,用 1、0 表示是否返回某个字段。筛选多个字段时,只能同时为 1 或 0 。

    • 例:
      db.c1.find({"name":"leo"}, {"_id": 1, "name": 1})
      
  • 查询结果的可用方法:

    db.<collection>.find().pretty()           // 显示时进行换行、缩进
                          .limit(10)          // 最多返回 10 个匹配的文档
                          .count()            // 不返回文档,而是计数
                          .sort({"_id":1})    // 按某个字段进行排序(1 表示升序,-1 表示降序)
    
    db.<collection>.find().pretty().limit(10) // 可嵌套使用多个方法
    
    • 使用 limit(n) 时,只要查询到 n 条文档就停止查询,不必遍历所有文档,因此查询耗时、占用内存少。
    • 如果直接执行 db.<collection>.count() ,则会估算集合的文档数,不会遍历所有文档,因此不一定准确。

#

db.<collection>.insertOne({...})            // 往集合中插入一个文档
db.<collection>.insertMany([{...}, {...}])  // 以数组的形式插入多个文档
  • 新增文档时,如果指定的集合不存在,则会自动创建它。
  • 默认将 _id 字段设置成主键,并建立索引。
    • 如果没有输入 _id 字段,则会自动添加。如果输入了 _id 字段,则会覆盖原来的值。
  • 每个集合可写入的文档数量没有上限,但单个 BSON 文档的体积最大为 16MB 。

#

db.<collection>.updateOne([query], <update>)   // 修改第一个匹配的文档
db.<collection>.updateMany([query], <update>)  // 修改所有匹配的文档
  • update 参数表示要执行的操作。
    • 例:
      db.c1.updateOne({"name":"leo"}, {$set:{"name":"Leo"}})
      
    • 常用的操作类型:
      $set      // 设置字段
      $unset    // 删除字段
      $rename   // 修改字段的名称。例如:$rename:{"a":"b"}
      $inc      // 对数字类型的字段进行加减
      $push     // 向 array 类型的字段中添加一个值。例如:$push:{"tags":"a"}
      $pushAll  // 向 array 类型的字段中添加多个值。例如:$push:{"tags":[1,2,3]}
      $pull     // 从 array 类型的字段中删除一个值。例如:$pull:{"tags":"a"}
      $pullAll  // 从 array 类型的字段中删除多个值。例如:$pull:{"tags":[1,2,3]}
      $pop      // 用 1、-1 分别表示删除最后一个值、第一个值。例如:$pop:{"tags":1}
      

#

db.<collection>.deleteOne([query])     // 删除第一个匹配的文档
db.<collection>.deleteMany([query])    // 删除所有匹配的文档

# index

  • 一个 collection 可以针对多个字段创建多个 index ,用于加速查询。
    • 每个集合默认有一个针对 _id 字段的索引,用户还可创建其它索引。
    • 支持创建由多个字段组成的复合索引。

#

db.<collection>.getIndexes()        // 显示所有索引
db.<collection>.totalIndexSize()    // 显示全部索引的大小

#

db.<collection>.createIndex(<keys>, [options])
  • 例:
    db.c1.createIndex({"title":1}, {"name": "index_1"})  // 对一个字段创建索引(1 表示升序,-1 表示降序)
    db.c1.createIndex({"title":1, "tags":-1})            // 对多个字段创建索引
    
  • 常用的 options 参数:
    • name :该索引的名称。未指定的话会自动命名。
    • unique :是否限制该字段的取值唯一。默认为 false 。
    • background :是否在后台创建索引。默认为 false ,会阻塞前台进程。
    • expireAfterSeconds :设置过期时间,过期之后一段时间内会自动删除该文档。(只能作用于 Date 类型的字段)
    • v :索引的版本号。

#

db.<collection>.dropIndex("name_1") // 删除指定索引
db.<collection>.dropIndexes()       // 删除所有索引

db.<collection>.reIndex()           // 重新建立索引,该操作的开销较大