MongoDB之CRUD基本操作与聚合框架的使用

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 MongoDB之CRUD基本操作与聚合框架的使用,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

MongoDB概述

MongoDB 是一款灵活、可扩展、高性能的 NoSQL 数据库,主要用于处理非结构化数据和大规模数据处理。它采用的是面向文档的数据模型,数据以 BSON(Binary JSON) 格式存储,支持动态查询和索引,可在分布式环境下运行。

特点和优势:

1.面向文档的数据模型:

MongoDB 存储的数据是以 BSON 格式表示的文档,与传统关系型数据库的表格模型不同,这样可以更好地处理非结构化数据和半结构化数据。

2.高性能和可扩展性:

MongoDB 支持水平扩展,可以通过添加更多的节点来增加系统的处理能力,同时还具有高性能的查询和索引能力,适用于大规模数据处理和高并发访问场景。

3.强大的查询和索引功能:

MongoDB 支持动态查询和索引,可以使用多种查询方式进行数据检索,同时还可以创建多种类型的索引来优化查询性能。

4.灵活的数据模型和数据一致性:

MongoDB 支持动态数据模型,可以方便地扩展和修改数据结构,同时还具有多种数据一致性选项,包括强一致性和最终一致性等。

5.开源和社区支持:

MongoDB 是一款开源软件,拥有庞大的社区支持和活跃的开发者社区,可以提供丰富的功能和优化。

MongoDB官方文档:https://docs.mongodb.com

MongoDB中文社区:http://www.mongoing.com

相关术语

在mongodb中是通过数据库、集合、文档的方式来管理数据,与关系型数据库类似。

SQL 术语/概念书 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 表连接(MongoDB不支持)
primary key primary key 主键,MongoDB自动在每个集合的文档中添加_id的主键

在这里插入图片描述

数据库

一个mongodb中可以建立多个数据库

Help查看命令提示

db.help();

切换/创建数据库(如果数据库不存在,则创建数据库,否则切换到指定数据库)

use test

查询所有数据库

show dbs;

删除当前使用数据库

db.dropDatabase();

查看当前使用的数据库

db.getName();

显示当前db状态

db.stats();

当前db版本

db.version();

查看当前db的链接机器地址

db.getMongo〇;

文档

文档是一组键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

RDBMS与MongoDB对应的术语

RDBMS MongoDB
数据库 数据库
表格 集合
文档
字段
表联合 嵌入文档
主键 主键 (MongoDB 提供了 key 为 _id )
需要注意的是:
文档中的键/值对是有序的

文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)

MongoDB区分类型和大小写

MongoDB的文档不能有重复的键

文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符

文档键命名规范:

键不能含有\0 (空字符)。这个字符用来表示键的结尾

.和$有特别的意义,只有在特定环境下才能使用

以下划线"_"开头的键是保留的(不是严格要求的)

集合

集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。

集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

创建一个集合(table)

db.createCollection( "collName");

得到指定名称的集合(table )

db.getCollection("user");

数据类型

数据类型 |描述
–|–|–
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的
Integer |整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位
Boolean |布尔值。用于存储布尔值(真/假)
Double |双精度浮点值。用于存储浮点值。
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Array |用于将数组或列表或多个值存储为一个键
Timestamp | 时间戳。记录文档修改或添加的具体时间
Object |用于内嵌文档
Null |用于创建空值
Symbol |符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言
Date |日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息
Object ID |对象 ID。用于创建文档的 ID
Binary Data |二进制数据。用于存储二进制数据
Code |代码类型。用于在文档中存储 JavaScript 代码
Regular expression | 正则表达式类型。用于存储正则表达式

连接命令格式

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

mongodb:// 固定前缀

username:账号,可不填

password:密码,可不填

host:主机名或ip地址,只有host主机名为必填项

port:端口,可不填,默认27017

/database:连接某一个数据库

?options:连接参数,key/value对

mongodb://localhost 连接本地数据库27017端口 

mongodb://root:123456@localhost 使用用户名root密码为123456连接本地数据库27017端口 

mongodb://localhost:27017,localhost:27018,localhost:27019,连接三台主从服务器,端口为27017、27018、27019

MongoDB基本操作

数据库操作

登录客户端

root@d8110bf377a7:/# mongo         
MongoDB shell version v5.0.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7f7b7e78-ffa1-4f8d-8c08-78800215cce0") }
MongoDB server version: 5.0.5

查询

show databases 查询全部数据库

show dbs 查询全部数据库
	
db 显示当前数据库

创建数据库

1.use DATABASE_NAME
use demodb  :有demodb数据库则切换过去,否则创建,新创建的数据库不显示,需要至少包括一个集合。

2.插入数据即刻创建数据库

删除数据库

使用 db.dropDatabase() 来删除数据库

数据库相应文件也会被删除,磁盘空间将被释放

先切换数据库:use demodb

再执行删除:db.dropDatabase()
use demo

db.dropDatabase()

集合(表)操作

集合相当于关系数据库中的表,一个数据库可以创建多个集合,一个集合是将相同类型的文档管理起来。

集合列表

show collections

创建集合

1.db.createCollection(name, options)

	name: 新创建的集合名称
	
	options: 创建参数
	
	db.createCollection(user) : 创建user集合

2.插入数据即可创建集合

更新集合名称

db.集合名.renameCollection("新的集合名称")

删除集合

db.<集合>.drop() 删除一个集合
	
集合中的全部文档都会被删除

集合相关的索引也会被删除
db.collection_name.drop()

db.user.drop()  : 删除user集合

文档操作

mongodb中文档的格式是json格式,使用 insert() 或 save() 方法向集合中插入文档

进入数据库,创建集合

> use demoDb
switched to db demoDb
> db.createCollection('user')
{ "ok" : 1 }
>

insert插入

insert单条数据

db.<集合>.insertOne(<JSON对象>)

insert多条数据

db.<集合>.insertMany([<JSON 1>, <JSON 2>,<JSON n>])

示例

db.COLLECTION_NAME.insert(document)
	
	db.demoDb.insert({"name":"lisi","age":12})
	
	{ 
    "_id" : ObjectId("5fc7a1a39b84bb20d9911830"), 
    "name" : "lisi", 
    "age" : 12.0
	}

每个文档默认以_id作为主键,主键默认类型为ObjectId(对象类型),mongodb会自动生成主键值。

Objectld是、id”的默认类型。Objectld使用12字节的存储空间,每个字节二位十六进制数字, 是一个24位的字符串

在这里插入图片描述

在这里插入图片描述

update更新

语法格式:

db.collection.update(
	   <query>,
	   <update>,
	   <options>
	)
query:查询条件,相当于sql语句的where

update:更新文档内容

options:选项

1、整体更新

将符合条件的第一个文档更新

db.user.update({"name" : "lisi"},{"name" : "wangwu", "age" : 22.0})

2、局部更新

使用$set修改器指定要更新的key,key不存在则创建,存在则更新。

db.user.update({"name" : "lisi"},{$set:{"age":22}})

3.批量更新

将符合条件的所有文档更新

db.user.update({"name" : "wangwu"},{$set:{"name" : "lisi", "age" : 33.0}},{multi:true})
	
multi:false表示更新第一个匹配的文档,true表示更新所有匹配的文档。
updateOne表示无论条件匹配多少条记录,始终只更新第一条

updateMany表示条件匹配多少条就更新多少条

updateOne/updateMany方法要求更新条件部分必须具有以下之一,否则将报错:

$set/$unset
$push/$pushAll/$pop
$pull/$pullAll
$addToSet
db.user.updateOne({"age":21},{$set:{"name":"name111"}})

更新数组

$push: 增加一个对象到数组底部

$pushAll: 增加多个对象到数组底部

$pop: 从数组底部删除一个对象

$pull: 如果匹配指定的值,从数组中删除相应的对象

$pullAll: 如果匹配任意的值,从数据中删除相应的对象

$addToSet: 如果不存在则增加一个值到数组

Remove删除

db.student.remove(<query>)

query:删除条件,相当于sql语句中的where

删除全部

db.user.remove({})

按条件删除

db.user.remove({"name":"wangwu"})
remove命令需要配合查询条件使用;

匹配查询条件的的文档会被删除;

指定一个空文档条件会删除所有文档;

find查询

# query:查询条件,可不填
# projection:投影查询key,可不填
db.collection.find(query, projection)

查询全部

db.user.find()

以格式化的方式来显示所有文档

db.集合名.find().pretty()

查询符合条件的记录

db.user.find({"age":33})	

投影查询

设置需要显示字段,一旦设置投影默认字段都不显示,需要手动设置字段为 1,如果是_id默认是显示,如果不显示可以把 _id 设置成 0

db.集合名称.find( {查询条件} , {_id : 0, 字段A : 1, 字段B : 1} ) 

# 设置查询条件  设置投影条件
db.user.find({name:"mongo"},{_id:0,name:1,age:1})

只显示name和age两个key,_id主键不显示。

db.user.find({"name":"lisi"},{name:1,age:1,_id:0})

排序

1升序,-1降序

db.user.find().sort({age:-1})

统计个数

db.user.find().count()

db.user.count({})

消除重复

# 去重字段 查询条件
db.user.distinct('name',{age:{$gt:20}})

查询子文档

搜索子文档,使用“field.sub_field”的形式查询子文档

{
    "_id": {
        "$oid": "61330facbf0bf2331163f17a"
    },
    "name": "测试",
    "age": 21,
    "address": {"name":"address1"}
  
}


db.user.find( { "address.name" : "address1"})

对数组查询

对数组中的元素进行搜索

{
    "_id": {
        "$oid": "61330facbf0bf2331163f17a"
    },
    "address": ["address1", "address2"]
}

db.user.find( { "address" : "address1"})

db.user.find( { $or: [{"address" : "address1"},{"address" : "address2"}]})

搜索数组中的对象

{
    "_id": {
        "$oid": "61330facbf0bf2331163f17a"
    },
    "users":[{"name":"name1","age":22},{"name":"name2","age":23}]  
}

db.user.find({"users.name":"name2"})

db.user.find({"users.name":"name2","users.age":23})

// 索子对象的多个字段时,如果使用 $elemMatch,它表示必须是同一个子对象满足多个条件。
db.user.find({"users":{$elemMatch:{"name":"name1","age":22}}})

比较运算符

$lt: 存在并小于

$lte: 存在并小于等于

$gt: 存在并大于

$gte: 存在并大于等于

$ne: 不存在或存在但不等于
db.user.find({age:{$gt:20}})

逻辑运算符

$and: 匹配全部条件

$or: 匹配两个或多个条件中的一个

单条件查询

db.user.find({"age":21});

多条件and查询

db.user.find({"name":"测试","age":21});

db.user.find({$and : [{"name":"测试"},{"age":21}]});

多条件 or 查询

db.user.find({$or : [{"name":"测试"},{"age":25}]});

范围运算符

$in: 存在并在指定数组中

$nin: 不存在或不在指定数组中
db.user.find(
  {
    name:{$nin:['java','vue']}
  }
)

正则表达式

db.user.find(
  {
    name:/^java*/
  }
)
db.user.find(
  {
    name:{$regex:"^java"}
  }
)

自定义查询

db.user.find(
  {
    $where: function(){
      // true 表示 符合条件,false 表示不符合条件
      // 1. 返回值 必须是 true 或者 false
      // 2. 在函数中的关键 this 表示当前记录
      if(this.name == "java"){
        return true
      } else {
        return this.age > 20 && this.age < 30
      }
    }
  }
)

limit和skip

limit 显示记录数

db.user.find().limit(2)

skip跳过记录

db.user.find().skip(1)

2者混合使用,不管先后先 skip 再 limit

db.user.find().limit(2).skip(1)
db.user.find().skip(1).limit(2)

查询条件对照表

SQL MQL
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: {$lte: 1}}

查询逻辑对照表

SQL MQL
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 IS NULL {a: {$exists: false}}
a IN (1, 2, 3) {a: {$in: [1, 2, 3]}}

索引操作

在MongoDB中,可以使用索引来加速数据的查询和排序操作。

语法格式:

db.collection.createIndex(keys, options)

插入10W数据

插入10万条数据到数据库中

use demo

for(i=0;i<100000;i++){db.user.insert({name:'test'+i,age:i})}

查询速度对比

db.user.find({name:'test1000'})

# 查询操作的详细信息
db.user.find({name:'test1000'}).explain('executionStats')

创建索引

#  1:指定按升序创建索引
# -1:指定按降序来创建索引
db.user.createIndex({"name":1})

创建唯一索引

默认情况下mongdb的索引域的值是可以相同的,创建唯一索引之后,数据库会在插入数据的时候检查创建索引域的值是否存在,如果存在则不会插入该条数据

可以根据唯一索引指定的字段的值,进行数据去重

db.user.createIndex({"name":1}, {"unique":true})

建立复合索引

设置使用多个字段创建索引。将名称name与年龄age等2个字段建立复合索引

db.user.createIndex({"name":1,"age":1})

查看集合索引

db.user.getIndexes()

删除索引

删除集合指定索引

db.user.dropIndex('索引名称')

删除集合所有索引

db.user.dropIndexes()

查看集合索引大小

db.user.totalIndexSize()

注意点

根据需要选择是否需要建立唯一索引

索引字段是升序还是降序在单个索引的情况下不影响查询效率,但是带复合索引的条件下会有影响

数据量巨大并且数据库的读出操作非常频繁的时候才需要创建索引,如果写入操作非常频繁,创建索引会影响写入速度

MongoDB聚合框架

MongoDB中聚合(aggregate)主要用于处理数据(如统计平均值,求和等),并返回计算后的数据结果。而find主要用于查询数据

MongoDB聚合框架(Aggregation Framework)是一个计算框架,它可以:

作用在一个或几个集合上

对集合中的数据进行的一系列运算

将这些数据转化为期望的形式

聚合框架相当于SQL查询中的:GROUP BY、 LEFT JOIN、 AS等

管道(Pipeline)和步骤(Stage)

整个聚合运算过程称为管道(Pipeline),它是由多个步骤(Stage)组成的,每个管道接受一系列文档(原始数据),每个步骤对这些文档进行一系列运算,结果文档输出给下一个步骤

聚合运算写法

db.集合名称.aggregate([
   {管道名 : {表达式}},
   {管道名 : {表达式}},
   {管道名 : {表达式}},
])
pipeline = [$stage1, $stage2, ...$stageN];

db.<COLLECTION>.aggregate(
	pipeline,
	{ options }
);

管道名

管道名 作用 SQL等价运算符
$project 和投影作用一样,可以让某些字段不显示。修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。 AS
$match 匹配出符合条件的数据,和find操作一致,用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。 WHERE
$limit 用来限制MongoDB聚合管道返回的文档数。 LIMIT
$skip 在聚合管道中跳过指定数量的文档,并返回余下的文档。 SKIP
$unwind 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group 按照某个字段进行分组,可用于统计结果。 GROUP BY
$sort 将输入文档排序后输出。 ORDER BY
$geoNear 输出接近某一地理位置的有序文档
$lookup 左外连接 LEFT OUTER JOIN
$graphLookup 图搜索
$facet $bucket 分面搜索

表达式

表达式 描述 实例
$sum 统计个数,按照数字进行累加 db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, num_tutorial : {

s

u

m

:

sum : ”

sum:likes”}}}])

$avg表示平均值db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, num_tutorial : {

a

v

g

:

avg : ”

avg:likes”}}}])

$min获取集合中所有文档对应值得最小值db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, num_tutorial : {

m

i

n

:

min : ”

min:likes”}}}])

$max获取集合中所有文档对应值得最大值db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, num_tutorial : {

m

a

x

:

max : ”

max:likes”}}}])

$push在结果文档中插入值到一个数组中db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, url : {

p

u

s

h

:

push: ”

push:url”}}}])

$addToSet在结果文档中插入值到一个数组中,但不创建副本db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, url : {

a

d

d

T

o

S

e

t

:

addToSet : ”

addToSet:url”}}}])

$first根据资源文档的排序获取第一个文档数据db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, first_url : {

f

i

r

s

t

:

first : ”

first:url”}}}])

$last根据资源文档的排序获取最后一个文档数据db.mycol.aggregate([{KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …roup : {_id : “by_user”, last_url : {

l

a

s

t

:

last : ”

last:url”}}}])

group 管道

按照某个字段进行分组,依次对每个组进行统计计算。 _id表示按照某个字段进行分组,但是内部的字段名称前面必须添加$字符,如果_id设置为 null å表示把所有数据作为一组看待。

$sum/$avg

$push/$addToSet

$first/$last/$max/$min
db.user.aggregate([
  {
    $group: {
      //  设置分组字段
      // _id:"$gender",
      _id:null,
      // 编写统计表达式
      // $sum 统计总数表达式
      // "总数":{$sum:3},
      // $avg 表示平均值
      "平均年龄":{$avg:"$age"},
      // "最大年龄":{$max:"$age"},
      // "最小年龄":{$min:"$age"}
      // "姓名":{$push:"$name"},
      // "xxx":{$push:"$$ROOT"}
    }
  }  
]).pretty()

match 管道

$eq/$gt/$gte/$lt/$lte

$and/$or/$not/$in

$geoWithin/$intersect
db.user.aggregate([
   {
     $match: {
       age:{$gt:15}
     }
    },
    {
      $group:{
        _id:"$name",
        "平均年龄":{$avg:"$age"},
        "最大年龄":{$max:"$age"}
      }
    }
])

project 管道

和投影一样,如果不设置就表示隐藏,如果设置为1表示表示显示,_id 默认是显示的,如果想让_id不显示可以设置为0

$map/$reduce/$filter

$range

$multiply/$divide/$substract/$add

$year/$month/$dayOfMonth/$hour/$minute/$second
db.user.aggregate([
  {
    $match:{
      age:{$gt:15}
    }
  },
  {
    $group:{
      _id:"$name",
      "平均年龄":{$avg:"$age"},
      "最大年龄":{$max:"$age"}
    }
  },
  {
    $project:{
      "_id":0,
      "平均年龄":1
    }
  }
])

sort 管道

1表示升序,-1表示降序

db.user.aggregate([
  {
    $match:{
      age:{$gt:15}
    }
  },
  {
    $sort:{
      age:1
    }
  }
])

limit管道 和 skip管道

limit管道和skip管道有先后次序因为是管道的作用

db.user.aggregate([
  {
    $match:{
      age:{$gte:20}
    }
  },
  {
    $limit:2
  },
  {
    $skip:1
  }
])

unwind 管道

按照某个字段进行数据拆分成多条记录,默认情况会过滤 列表为空,列表为 null 字段不存在的数据,如果想要不过滤数据使用preserveNullAndEmptyArrays:true

db.user.aggregate([
  {
    $unwind:'$age'
  }
])

// 不过滤数据
db.user.aggregate([
  {
    $unwind: {
      // 设置拆分字段
      path:'$age',
      // 设置不过滤数据
      preserveNullAndEmptyArrays:true
    }
  }
])

混合使用

db.user.aggregate([
		{$match: {age: 21}},
		{$skip: 5},
		{$limit: 10},
		{$project: {
			'名称': '$username',
		}}
]);

{ _id: ObjectId("613329f36294f81cb1c96092"), '名称': 'test' }

复制集的作用

MongoDB 复制集的主要意义在于实现服务高可用

它的现实依赖于两个方面的功能:

数据写入时将数据迅速复制到另一个独立节点上

在接受写入的节点发生故障时自动选举出一个新的替代节点

在实现高可用的同时,复制集实现了其他几个附加作用:

数据分发:将数据从一个区域复制到另一个区域,减少另一个区域的读延迟

读写分离:不同类型的压力分别在不同的节点上执行

异地容灾:在数据中心故障时候快速切换到异地

复制集结构

一个典型的复制集由3个以上具有投票权的节点组成,包括:

一个主节点(PRIMARY):接受写入操作和选举时投票

两个(或多个)从节点(SECONDARY):复制主节点上的新数据和选举时投票

不推荐使用 Arbiter(投票节点)

数据是如何复制的

当一个修改操作,无论是插入、更新或删除,到达主节点时,它对数据的操作将被记录下来(经过一些必要的转换),这些记录称为 oplog。

从节点通过在主节点上打开一个 tailable 游标不断获取新进入主节点的 oplog,并在自己的数据上回放,以此保持跟主节点的数据一致。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137004.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!