认识 MongoDB 文档数据库的基本操作

发表于 2023-02-14

概述

MongoDB 文档数据库的 SQL 有异于我们熟知的关系型数据库(MySQL)的 SQL。

数据库

  • 选择数据库
    • use test
  • 创建数据库
    • 如果数据库中没有集合等数据,数据库实际不会被创建。
    • use test
  • 查看所有数据库
    • show dbs
  • 查看当前再哪个数据库下
    • db
    • 这个 db 可以看成是当前数据库的引用,后续的集合(表)、文档(数据)的操作会通过它来。
  • 删除数据库
# 先选择想要删除的数据库:test。
use test
# 再执行删除数据库的命令。
db.dropDatabase()

集合(表)

  • 查看集合
    • 两种用法都是支持的。
    • show tables
    • show collections
  • 删除集合
    • 语法
      • db.<collection_name>.drop()
    • 例子
      • db.test.drop()
  • 创建集合
    • 直接向集合里添加数据,如果集合不存在就会自动创建。
    • 例子
      • db.test.insertOne({...})

文档(记录)

开始操作文档(数据、记录)需要明确 MongoDB 的 SQL 和 MySQL 这类的关系型数据的 SQL 不一样了。

例如 MySQL 的 SQL 查询满足条件 age = 10 的数据。

SELECT field_a, field_b FROM table_a WHERE age = 10

但是 MongoDB 的 SQL 查询就是这样的。

{
    "age": {
        $eq: 10
    }
}

更新、聚合或者删除等操作也是类似的 SQL 结构。

更新操作符

  • 官方文档
  • 字段操作
    • $set
      • 添加或者更新一个字段及值。
      • { $set: { <newField>: <expression>, ... } }
    • $unset
      • 声明不发生更新的字段。
      • 如果一个字段不指定 $unset,也不使用 $set,将会认为更新后的数据不包含该字段,所以这些字段会被更新操作所覆盖删除。
      • { $unset: "<field1>" }
      • { $unset: [ "<field1>", "<field2>", ... ] }
    • $rename
      • 将字段重命名。
  • 数组操作
    • $push
      • 向数组中推入一个数据(文档)。
      • { $push: { <field>: <value>, ... }}
    • $pop
      • 向数组中取出一个数据(文档)。
      • { $pop: { <field>: <-1 | 1>, ... }}
      • 值为 -1 表示移除数组的第一个。
      • 值为 1 表示移除数组最后一个。
    • $pull
      • 从数组中删除符合条件的数据(文档)。
      • { $pull: { <field>: <value>, ... }}
      • 例如我要删除数组中的字符串 c
      • ["a", "b", "c", "c"] --> pull "c" --> ["a", "b"]
    • $pullAll
      • 从数组中删除符合任何一个条件的数据(文档)。
      • { $pull: { <field>: [<value>], ... }}
      • 例如我要删除数组中的字符串 cb
      • ["a", "b", "c", "c"] --> pull ["c", "b"] --> ["a"]
    • $addToSet
      • 不存在则添加一个值,存在则不添加。
      • { $addToSet: { <field>: <value>, ... }}

逻辑操作符

  • $and
    • 并且:表示多个条件都要满足的文档,等效 AND
    • {$and: [{<expression>}, {<expression>}]}
  • $not
    • 不等于:表示查询不满足表达式的文档,等效 !=
    • {$not: {<expression>}}
  • $or
    • 或者:表示查询满足任意一个表达式的文档,等效 OR
    • {$or: [{<expression>}, {<expression>}]}
  • $nor
    • 返回所有未能同时匹配这两个子句的

关系运算符

  • $eq
    • 等于
    • {<field>: {$eq: <value>}}
  • $gt
    • 大于
    • {<field>: {$gt: <value>}}
  • $gte
    • 大于等于
    • {<field>: {$gte: <value>}}
  • $in
    • IN
    • {<field>: {$in: [<value>, ...]}}
  • $lt
    • 小于
    • {<field>: {$lt: <value>}}
  • $lte
    • 小于等于
    • {<field>: {$lte: <value>}}
  • $ne
    • 不等于
    • {<field>: {$ne: <value>}}
  • $nin
    • NOT IN
    • {<field>: {$nin: [<value>, ...]}}

数组查询符

  • $elemMatch
    • 查询数组中存在元素(至少一个匹配)。
    • {<field>: {$elemMatch: { <query1>, <query2>, ...}}}
  • $size
    • 匹配数组长度。
    • {field: {$size: size}}

数据操作

添加文档

  • _id
    • 每个文档都需要一个再集合中不重复的 id 作为作为主键。
    • 如果创建时没有指定,就会自动生成一个 ObjectId 作为 id 的值。
  • 语法
    • db.<collection_name>.insert(<document or array of documents>, {writeConcern: <document>, ordered: <boolean>})
      • 添加数据:第一个参数是数据、第二个参数是一些配置项。有如下两个示例:
      • writeConcern
        • MongoDB 的写入策略。
        • 一般同事务一同使用,例如服务器写入磁盘才应答。
      • ordered
        • true:有序的插入,中间报错后,后续的不再处理(默认值)。
        • false:无序的插入,中间报错后,继续处理后续的文档插入操作。
    • db.<collection_name>.insertOne(<json_string>)
      • 添加单条
    • db.<collection_name>.insertMany([<json_string>, ...])
      • 添加多条
# 添加数据
db.test.insert({...})
db.test.insert([{...}, {...}])
# 添加一条
db.test.insertOne({...})
# 添加多条
db.test.insertMany([{...}, {...}])

更新文档

  • options
{
    # true:等同于 updateMany()
    # false:只更新命中的第一条(默认值)
    upsert: <boolean>,
    writeConcern: <document>,
    # 指定排序规则
    collation: <document>,
    # 更新数组的筛选条件
    arrayFilters: [ <filterdocument1>, ... ],
    # 选择索引
    hint:    <document|string>
}

################################ arrayFilters 例子 ################################
# 数据如下
#  {"_id": 1, "grades": [ 95, 92, 90]}
#  {"_id": 2, "grades": [ 98, 100, 102]}
#  {"_id": 3, "grades": [ 95, 110, 100]}
# 将 grades 数组中大于等于 100 的值更新为 100
db.students.updateMany(
    { grades: { $gte: 100 } },
    { $set: { "grades.$[element]" : 100 } },
    { arrayFilters: [ { "element": { $gte: 100 } } ] }
)
  • 语法
    • db.<collection_name>.update(query, update, options)
      • 更新数据
    • db.<collection_name>.updateOne(query, update, options)
      • 更新命中的第一条数据
    • db.<collection_name>.updateMany(query, update, options)
      • 更新多条数据
db.test.update({"age": 10},{$set: {"name": "update name"}})
# 只更新命中的第一条数据
db.test.updateOne({"age": 10},{$set: {"name": "updateOne"}})
# 更新数据,根据 age = 10 的条件,更新 name = "new name"
db.test.updateMany({"age": 10},{$set: {"name": "new name"}})

查询文档

  • 查询语法
    • db.<collection_name>.find(query)
    • db.<collection_name>.findOne(query)
  • 分页
    • db.<collection_name>.find(query).skip(offSet).limit(size)
  • 排序
    • db.<collection_name>.find(query).sort({name: 1})
# 查看所有
db.test.find()
# 分页
db.test.find().skip(1).limit(1)
# 根据条件做查询,查询条件为 age = 10
db.test.find({"age": {$eq: 10}})
# 随便返回一个文档
db.test.findOne()
# 根据条件命中
db.test.findOne({"age": {$eq: 10}})
# 某个字段存在
db.test.find({"score": {$exists: true}})

删除文档

  • 语法
    • db.<collection_name>.deleteOne(filter, options)
      • 删除一个
    • db.<collection_name>.deleteMany(filter, options)
      • 删除多个
# 删除匹配中的一个
db.test.deleteOne({"age": {$eq: 10}})
# 删除所有
db.test.deleteMany({})
# 删除所有匹配中的
db.test.deleteMany({"age": {$eq: 10}})