Mongodb简单使用语法和聚合管道介绍

174 阅读7分钟

介绍

MongoDB 数据模型是面向文档的, 所谓文档就是一种类似于 JSON 的结构, 简单理解 MongoDB 这个数据库中存在的是各种各样的 JSON(BSON)

  • 数据库 (database)

    • 数据库是一个仓库, 存储集合 (collection)
  • 集合 (collection)

    • 类似于数组, 在集合中存放文档
  • 文档 (document)

    • 文档型数据库的最小单位, 通常情况, 我们存储和操作的内容都是文档

在 MongoDB 中, 数据库和集合都不需要手动创建, 当我们创建文档时, 如果文档所在的集合或者数据库不存在, 则会自动创建数据库或者集合

基础语法

2.1 数据库 (databases) 管理语法

操作语法
查看所有数据库show dbs;show databases;
查看当前数据库db;
切换到某数据库 (若数据库不存在则创建数据库)use <db_name>;
删除当前数据库db.dropDatabase();

2.2 集合 (collection) 管理语法

操作语法
查看所有集合show collections;
创建集合db.createCollection("<collection_name>");
删除集合db.<collection_name>.drop()

2.3 新增文档

使用 db.<collection_name>.insertOne() 向集合中添加一个文档, 参数一个 json 格式的文档 -db.collection.insertOne() 用于向集合插入一个新文档,语法格式如下

db.collection.insertOne(
 {
    "name": "zhangsan",
     "age": "18"
 }
)

使用 db.<collection_name>.insertMany() 向集合中添加多个文档, 参数为 json 文档数组 db.collection.insertMany() 用于向集合插入一个多个文档,语法格式如下:


db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

//-----------------------
db.collection.insertMany(
   [{
    "name": "zhangsan",
     "age": "18"
      },
      {
    "name": "lisi",
     "age": "20"
 }])

参数说明:

  • document:要写入的文档。
  • writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。
  • ordered:指定是否按顺序写入,默认 true,按顺序写入
  • mongo 中的数字, 默认情况下是 double 类型, 如果要存整型, 必须使用函数 NumberInt(整型数字), 否则取出来就有问题了
  • 插入当前日期可以使用 new Date()

2.4 查询

使用 db.<collection_name>.find() 方法对集合进行查询, 接受一个 json 格式的查询条件. 返回的是一个数组

使用 db.<collection_name>.findOne() 查询集合中符合条件的第一个文档, 返回的是一个对象

// 插入多条记录
> db.comment.insertMany([
{"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
{"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
{"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
{"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
{"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}
]);
{
        "acknowledged" : true,
        "insertedIds" : [
                "1",
                "2",
                "3",
                "4",
                "5"
        ]
}

// 只返回查询到的第一条数据
> db.comment.findOne({"articleid":"100001"})
{
        "_id" : "1",
        "articleid" : "100001",
        "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。",
        "userid" : "1002",
        "nickname" : "相忘于江湖",
        "createdatetime" : ISODate("2019-08-05T22:08:15.522Z"),
        "likenum" : 1000,
        "state" : "1"
}
// 等价于
db.comment.find({"articleid":"100001"}).limit(1)

如果我们不需要那么多的字段,我们可以在查询条件后面再跟上需要查询的字段,1表示显示指定的字段,其中_id是默认显示的,我们指定0表示强制不显示

javascript代码解读复制代码
// 只显示articleid字段
> db.comment.find({"articleid":"100001"},{"articleid":1}).limit(1)
{ "_id" : "1", "articleid" : "100001" }
// 强制_id不显示
> db.comment.find({"articleid":"100001"},{"articleid":1,"_id":0}).limit(1)
{ "articleid" : "100001" }
2.4.1 查询条件对照表
SQLMQL
a=1{a: 1}
a<>1{a:{$ne: 1}}
a>1{a:{$gt: 1}}
a>=1{a:{$gte: 1}}
a<1{a:{$lt: 1}}
a<=1{a:{$le: 1}}
2.4.2 查询逻辑对照表
SQLMQL
a=1 AND b=1{a:1,b:1}或者{$and:[{a: 1},{b: 1}]}
a=1 OR b=1{$or:[{a: 1},{b: 1}]}
a=1 IS NULL{a:{$exists: false}}
a=IN (1,2,3){a:{$in:[1,2,3]}}
2.4.3 指定排序

在mongodb使用sort()方法排序

db.collection.find().sort("字段名"1)
//--------------------------------- 1正序-1倒序
2.4.4 分页查询

skip用于指定跳过记录数,limit则用于限定返回的数量

db.collection.find().skip(8).limit(3)
//-----------------------跳过前面8行数据只返回3行数据
2.4.5 正则表达式匹配查询

$regex 操作符是用来设置匹配字符串的正则表达式

db.collection.find({"字段名":{$regex:"查询内容"})

2.5 修改文档

  • 使用 db.<collection_name>.updateOne(<filter>, <update>, <options>) 方法修改一个匹配 <filter> 条件的文档
  • 使用 db.<collection_name>.updateMany(<filter>, <update>, <options>) 方法修改所有匹配 <filter> 条件的文档
  • 使用 db.<collection_name>.findAndModify(<filter>, <update>, <options>) 方法修改所有匹配 <filter> 条件的文档,默认返回修改前的旧数据,可以指定new用来返回修改后的新数据
db.<collection_name>.findAndModify({
  quer:{字段名,内容},
  update:{修改方法},
  newtrue
})
  • 使用 db.<collection_name>.replaceOne(<filter>, <update>, <options>) 方法替换一个匹配 <filter> 条件的文档
  • db.<collection_name>.update(查询对象, 新对象) 默认情况下会使用新对象替换旧对象
  • filter: 描述更新的查询条件
  • update: 描述更新的动作及新增的内容
  • options:描述更新的选项
  1. upsert 可选,如果不存在update的记录,是否插入新的数据。默认是false,不插入

    1. multi 可选,是否按照条件将查询出的多条记录全部更新,默认是false,只更新找到的第一条数据
    2. writeConcer: 可选,决定一个操作落到多少个节点才算成功
2.5.1 更新的操作符
操作符格式描述
$set{$set:{field:value}}指定一个键并更新,如果不存在就创建
$unset{$unset:{field: 1}}删除一个键
$inc{$$inc:{field: value}}对数值类型进行增减
$rename{$rename:{old_field_name:new_field_name}}修改字段名
$push{$push:{field:value}}将数值追加到数组中,若数组不存在则进行初始化
$pushAll{$pushAll:{field:value_array}}追加多个值到一个数组的字段内
$pull{$pull:{field_value}}从数组中删除 指定的元素
$addToSet${addToSet:{field:value}}添加元素到数组中,具有排重功能
$pop{$pop:{field:1}}删除数组中的第一个或者是最后一个元素(1为末尾元素,-1为开头元素)

2.6 删除文档

2.6.1 使用remove删除文档
  • remove命令需要配合查询条件使用
  • 匹配查询条件的文档会被删除
  • 指定一个空文档条件会删除所有记录
//删除文档与查询条件相同的记录
db.<collection_name>.remove({查询条件}) 

 // 删除所有记录
db.<collection_name>.remove({})

 // 只删除与条件匹配的一个文档justOne(布尔类型)true为只删除一个
db.<collection_name>.remove({查询条件},justOne)

  // 错误写法
db.<collection_name>.remove()
2.6.2 delect删除文档

官方推荐使用deleteOne()和deleteMany()方法删除文档

// 删除集合下的所有文档
db.<collection_name>.deleteMany({})
// 删除满足查询条件的所有文档
db.<collection_name>.deleteMany({查询条件})
// 删除满足查询条件的一个文档
db.<collection_name>.deleteOne({查询条件})

聚合

3.1 单一聚合

函数描述
db.<collection_name>.estimateDoncumentCount()忽略查询条件,返回 所有文档的计数
db.<collection_name>.count()返回与find()集合或者是视图的查询匹配的文档计数。等同于db.<collection_name>find(query).count()
db.<collection_name>.distinct()在单个集合或者是视图中查找指定字段的不同值,并在数组中返回结果

3.2 aggregate()

是一个强大的聚合操作方法,用于对集合中的文档进行数据处理和分析

3.2.1 基础语法
db.collection.aggregate(pipeline, options);

collection是要进行聚合操作的集合名称,pipeline是一个由多个聚合阶段组成的数组,每个阶段都对数据进行特定的处理和转换,options是可选参数,用于指定一些聚合操作的额外选项,如排序规则、最大内存使用限制等。

3.3 管道集合

3.3.1 $project

$project是聚合管道中的一个阶段,主要用于对文档中的字段进行处理和投影,决定哪些字段要在输出结果中显示、隐藏或进行修改等

  • 当指定字段为 1 表示要显示该字段,为 0 表示不显示该字段,但_id字段默认是显示的,如果不想显示_id字段,需要明确指定_id: 0
  • $project阶段通常在聚合管道的较早阶段使用,以便在后续阶段中只处理需要的字段,提高性能。

主要作用

  1. 指定输出字段

可以明确指定要在结果中包含哪些字段,不指定的字段则不会出现在输出结果中

db.collection.aggregate([{
  $project: {
      name: 1,
      age: 1
    }
}]);

这将只返回文档中的nameage字段,其他字段则被排除。

  1. 重命名字段

可以给字段赋予新的名称

db.collection.aggregate([{
  $project: {
      newName: "$name",
      age: 1
    }
}]);

这里将原文档中的name字段重命名为newName在结果中显示,同时还包含age字段。

  1. 计算新字段

通过表达式可以根据已有字段计算出新的字段

db.collection.aggregate([{
  $project: {
      name: 1,
      age: 1,
      fullName: { $concat: ["$firstName", " ", "$lastName"] }
    }
}]);

假设原文档中有firstNamelastName字段,这里通过$concat操作符将它们拼接起来生成一个新的fullName字段并在结果中显示。

  1. 嵌套字段处理

可以对嵌套在文档中的字段进行投影和处理

// 原数据
{
  _id: 1,
  person: {
    name: "John",
    age: 30,
    address: {
      city: "New York",
      state: "NY"
    }
  }
}


// 函数使用
db.collection.aggregate([{   $project: {    "person.name": 1,    "person.address.city": 1  }}]);

只返回person对象中的nameaddress对象中的city字段。

3.3.2 $match

主要用于对输入的文档进行筛选 用法与查询中find()一致

尽量放到管道开始阶段减少后续操作文档数

db.collection.aggregate([{
   $match: {
      // 年龄等于20"age": 20
  }
}]);
3.3.2 $count

计数并返回与查询匹配的结果数

db.collection.aggregate([{
   $match: {
      // 年龄等于20"age": 20
  }
},
{
      // 将统计出来的数值分配给age_number字段
      $count:"age_number"
}]);

3.3.3 $unwind

  1. 将数组拆分成单独的文档
  2. 当对包含大量数据的集合进行$unwind操作时,可能会导致生成大量的中间文档,这可能会对性能和资源使用产生影响。因此,在实际应用中,需要谨慎考虑是否真的需要展开数组,以及如何结合其他聚合操作符来优化查询
  3. 如果数组字段为空数组,在默认情况下,使用$unwind操作后,该文档会被移除。不过,可以通过设置preserveNullAndEmptyArrays选项为true来保留这些文档
{
  $unwind:{
// 要指定的字段路径,在字段名称前加上$符号并用引号括起来
    path: <dield_path>
// 可选,一个新字段的名称用来存放元素的数组索引,该名称不能用$开includArratIndx: <String>
// 可选,default: false 若为true,如果路径为空,缺少或为空数组,则$unwind输出文档】
    preserveNullAndEmptyArrays:<boolean>
  }
}

案例:

// 假设我们有一个名为students的集合,其中的文档结构如下:
{
    "name": "Alice",
    "scores": [80, 90, 95]
}

// 使用语法
db.students.aggregate([
    {
        $unwind: "$scores"
    }
]);

// 输出结果
{
    "name": "Alice",
    "scores": 80
},
{
    "name": "Alice",
    "scores": 90
},
{
    "name": "Alice",
    "scores": 95
}