MongoDB是一个开源、跨平台、分布式文档数据库,属于NoSQL(Not Only SQL)数据库的一种。
Mac版官方文档:在macOS上安装MongoDB Community Edition
目录
1 MongoDB概述
MongoDB是一个面向文档的数据库,使用文档(document)对象存储数据
可扩展: 可以将数据分布式存储到多个服务器中,同时可以自动管理跨节点的负载均衡,将数据操作路由到相应的服务器。
MongoDB简单易用,功能丰富,数据存储性能高。
1.1 数据格式
在MongoDB中,数据使用JSON或者BSON格式进行处理和存储。
- JSON(JavaScript Object Notation):一种轻量级的数据交换格式,一个JSON文档就是一个由字段和值组成的集合,遵循特定的格式。
- BSON(Binary JSON):一种类 JSON 文档的二进制序列化,BSON更注重存储和处理的效率。
由于MongoDB本身不支持SQL语句,因此在初始化数据时常直接导入JSON等格式文件,或通过insertOne()
等插入语句将JSON数据进行插入。
1.2 文档(Document)
MongoDB以BSON文档的形式存储数据记录,简称为文档(Document)。
结构如下:
{
field_name1: value1,
field_name2: value2,
field_name3: value3,
...
}
实例:
{
_id: ObjectId("5f339953491024badf1138ec"),
title: “数据库系统概论",
isbn: “9787040406641",
publisher: “高等教育出版社",
published_date: new Date(‘2014-9-01'),
author: { first_name: “珊", last_name: "王"}
}
1.3 集合(Collection)
MongoDB使用集合(Colletion)存储文档,一个集合就是一组文档。
新建数据库后,应使用createCollection()
语句新建集合,之后即可进行数据操作。
MongoDB | RDBMS |
---|---|
文档 | 行 |
集合 | 表 |
特点:
- 集合的模式为动态的,集合中的文档结构可以完全不同
- 一个集合拥有一个名字
- 集合的名字不能包含以下内容
$
字符- null(
\0
)字符 - 空字符串
- 以
system
开头
1.4 数据库(DataBase)
集合(Collection)存储在数据库中,一个MongoDB实例可以包含多个数据库。
admin、local和config为系统保留数据库名称,不能使用这些名字创建新的数据库。
2 数据类型
- 空类型
- 布尔类型
- 数字类型
- 字符串类型
- 日期类型
- 正则表达式
- 数组类型
- 嵌入式文档
- 对象ID
3 创建文档
3.1 insertOne()
3.1.1 不指定_id
db.products.insertOne({
"name": "xiaomi",
"price": 799,
"releaseDate": ISODate("2019-05-14"),
"spec": {"ram": 4, "screen": 6.5, "cpu": 2.66},
"color": ["white", "black"],
"storage": [64,128,256]
});
{
acknowledged: true,
insertedId: ObjectId("65413081059fcf9ea192cda6")
}
3.1.2 指定_id
db.products.insertOne({
"_id": 2,
"name": "huawei",
"price": 899,
"releaseDate": ISODate("2021-09-01"),
"spec": {"ram": 16,"screen": 9.5,"cpu": 3.66},
"color": ["white", "black", "purple"],
"storage": [128, 256, 512]
});
{
acknowledged: true,
insertedId: 2
}
3.1.3 _id冲突
db.products.insertOne({
"_id": 2,
"name": "sanxing",
"price": 1299,
"releaseDate": ISODate("2018-01-14"),
"spec": { "ram": 12, "screen": 9.7, "cpu": 3.66 },
"color": ["blue"],
"storage": [16, 64, 128]
});
MongoServerError: E11000 duplicate key error collection: course.products index: _id_ dup key: { _id: 2 }
3.2 insertMany()
3.2.1 顺序插入
db.products.insertMany([
{
"_id": 1,
"name": "xiaomi",
"price": 799,
"releaseDate": ISODate("2021-05-14"),
"spec": { "ram" : 4, "screen" : 6.5, "cpu" : 2.66 },
"color": ["white", "black"],
"storage":[64, 128, 256]
},
{
"_id": 2,
"name": "huawei",
"price": 899,
"releaseDate": ISODate("2022-09-01") ,
"spec": { "ram" : 16, "screen" : 9.5, "cpu" : 3.66 },
"color": ["white", "black", "purple"],
"storage":[128, 256, 512]
},
{
"_id": 3,
"name": "sanxing",
"price": 899,
"releaseDate": ISODate("2023-01-14"),
"spec": { "ram" : 12, "screen" : 9.7, "cpu" : 3.66 },
"color": ["blue"],
"storage":[16, 64, 128]
}
])
MongoServerError: E11000 duplicate key error collection: course.products index: _id_ dup key: { _id: 1 }.
使用顺序插入,在_id
有冲突的情况下,所有文档均未插入
3.2.2 无序插入
db.products.insertOne({
"_id": 2,
"name": "sanxing",
"price": 1299,
"releaseDate": ISODate("2018-01-14"),
"spec": { "ram": 12, "screen": 9.7, "cpu": 3.66 },
"color": ["blue"],
"storage": [16, 64, 128]
});
MongoServerError: E11000 duplicate key error collection: course.products index: _id_ dup key: { _id: 2 }
无序插入的情况与有序插入不同,此时_id
为3的文档已经插入。
4 查找文档
4.1 findOne()
【例1】查找products集合中的第一个文档
db.products.findOne();
{
_id: ObjectId("65413081059fcf9ea192cda6"),
name: 'xiaomi',
price: 799,
releaseDate: 2019-05-14T00:00:00.000Z,
spec: {
ram: 4,
screen: 6.5,
cpu: 2.66
},
color: [
'white',
'black'
],
storage: [
64,
128,
256
]
}
【例2】查找_id
为3的文档
db.products.findOne({_id: 3})
{
_id: 3,
name: 'sanxing',
price: 899,
releaseDate: 2023-01-14T00:00:00.000Z,
spec: {
ram: 12,
screen: 9.7,
cpu: 3.66
},
color: [
'blue'
],
storage: [
16,
64,
128
]
}
【例3】查找_id
等于2的文档,只返回_id
和name
db.products.findOne({_id: 2}, {name: 1})
{
_id: 2,
name: 'huawei'
}
4.2 find()
【例1】查找products的所有文档
db.products.find();
返回products中所有文档(默认20个文档一页,通过it来翻页)
【例2】查找name
为huawei的文档
db.products.find({name: 'huawei'})
{
_id: 2,
name: 'huawei',
price: 899,
releaseDate: 2021-09-01T00:00:00.000Z,
spec: {
ram: 16,
screen: 9.5,
cpu: 3.66
},
color: [
'white',
'black',
'purple'
],
storage: [
128,
256,
512
]
}
【例3】查找name
为xiaomi的文档,返回_id
、price
和spec
中的ram
db.products.find({name: 'xiaomi'}, {_id: 1, price: 1, 'spec.ram': 1})
{
_id: ObjectId("65413081059fcf9ea192cda6"),
price: 799,
spec: {
ram: 4
}
}
4.3 比较运算符
比较运算符 | 等价于MySQL关系运算符 |
---|---|
$eq |
== |
$gt |
> |
$gte |
>= |
$lt |
< |
$lte |
<= |
$ne |
!= |
$in |
in |
$nin |
not in |
【例1】$gt
示例
db.products.find({'spec.ram': {$gt: 4}},{_id: 1, name: 1, 'spec.ram': 1})
{
_id: 2,
name: 'huawei',
spec: {
ram: 16
}
}
{
_id: 1,
name: 'sanxing',
spec: {
ram: 12
}
}
{
_id: 3,
name: 'sanxing',
spec: {
ram: 12
}
}
{
_id: 4,
name: 'SmartPad',
spec: {
ram: 8
}
}
【例2】$in
示例:查找ram
是4或8的文档信息
db.products.find({'spec.ram': {$in: [4,8]}}, {_id: 1, name: 1, 'spec.ram': 1})
{
_id: ObjectId("65413081059fcf9ea192cda6"),
name: 'xiaomi',
spec: {
ram: 4
}
}
{
_id: 4,
name: 'SmartPad',
spec: {
ram: 8
}
}
{
_id: 5,
name: 'SmartPhone',
spec: {
ram: 4
}
}
其他语法详见官方文档
5 练习
实践出真知
5.1 例1
使用元素运算符中的$exists
和$type
构建查询语句,并给出结果
db.course.find({ Cpno: { $exists: true } });
{ "Cno" : "1", "CName" : "数据库", "Cpno" : "5", "Ccredit" : 4 }
{ "Cno" : "3", "CName" : "信息系统", "Cpno" : "1", "Ccredit" : 4 }
{ "Cno" : "4", "CName" : "操作系统", "Cpno" : "6", "Ccredit" : 3 }
{ "Cno" : "5", "CName" : "数据结构", "Cpno" : "7", "Ccredit" : 4 }
{ "Cno" : "7", "CName" : "PASCAL语言", "Cpno" : "6", "Ccredit" : 4 }
db.student.find({ Sname: { $type: "string" } });
{ "sno" : "201215121", "sname" : "李勇", "Ssex" : "男", "Sage" : 20, "Sdept" : "CS" }
{ "sno" : "201215122", "sname" : "刘晨", "Ssex" : "男", "Sage" : 19, "Sdept" : "CS" }
{ "sno" : "201215125", "sname" : "张丽", "Ssex" : "男", "Sage" : 19, "Sdept" : "IS" }
{ "sno" : "201215130", "sname" : "刘%", "Ssex" : "女", "Sage" : 21, "Sdept" : "MA" }
5.2 例2
使用数组运算符中的$size
、$all
和$elemMatch
构建查询语句,并给出结果
db.sc.aggregate([
{ $group: { _id: "$sno", count: { $sum: 1 } } },
{ $match: { count: 2 } }
]);
{ "_id" : "201215122", "count" : 2 }
db.sc.find({ $all: [{ Grade: "1" }, { Grade: "2" }] });
{ "sno" : "201215121", "cno" : "1", "Grade" : "92" }
{ "sno" : "201215121", "cno" : "2", "Grade" : "85" }
db.sc.find({
$elemMatch: { Grade: { $gt: 70 } }
});
{ "sno" : "201215121", "cno" : "1", "Grade" : "92" }
5.3 例3
使用sort()
、skip()
和limit()
构建查询语句,并给出结果
db.course.find().sort({ Ccredit: -1 }).skip(2).limit(2);
{ "Cno" : "4", "CName" : "操作系统", "Cpno" : "6", "Ccredit" : 3 }
{ "Cno" : "2", "CName" : "数学", "Cpno" : null, "Ccredit" : 2 }
5.4 例4
使用updateOne()
和updateMany()
,结合$inc
、$min
、$max
、$mul
、$unset
、$rename
,构建更新语句,并给出结果
db.course.updateOne(
{ Ccredit: 4 },
{ $set: { Ccredit: 5 } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
db.course.updateMany(
{},
{ $inc: { Ccredit: 1 } }
);
{ "acknowledged" : true, "matchedCount" : 7, "modifiedCount" : 7 }
db.student.updateOne(
{ sno: '201215121' },
{ $min: { Sage: 21 } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
db.student.updateMany(
{},
{ $mul: { Sage: 2 } }
);
{ "acknowledged" : true, "matchedCount" : 4, "modifiedCount" : 4 }
db.student.updateOne(
{ sno: '201215122' },
{ $unset: { Ssex: "" } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
db.student.updateOne(
{ sno: '201215125' },
{ $rename: { Sdept: "Department" } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
5.5 例5
使用deleteOne()
和deleteMany()
构建删除语句,并给出结果
db.course.deleteOne({ CName: "数据库" });
{ "acknowledged" : true, "deletedCount" : 1 }
db.course.deleteMany({ Ccredit: { $lt: 3 } });
{ "acknowledged" : true, "deletedCount" : 2 }
5.6 例6
给出聚合操作aggregate()
的使用方法,说明其与find()
的差别,并给出实例
db.sc.aggregate([
{ $group: { _id: "$cno", avgGrade: { $avg: "$Grade" } } }
]);
{ "_id" : "1", "avgGrade" : 82 }
{ "_id" : "2", "avgGrade" : 80 }
5.7 例7
简述如何在mongoDB中实现多表关联查询,并给出实例
db.sc.aggregate([
{
$lookup: {
from: "course",
localField: "cno",
foreignField: "Cno",
as: "courseInfo"
}
}
]);
{
"sno" : "201215121",
"cno" : "1",
"Grade" : "92",
"courseInfo" : [ { "Cno" : "1", "CName" : "数据库", "Cpno" : "5", "Ccredit" : 4 } ]
}