整理自菜鸟教程
MongoDB基础概念
SQL术语 | MongoDB术语 | 说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接, MongoDB不支持 | |
primary key | primary key | 主键, MongoDB自动将_id字段设置为主键 |
MongoDB将数据存储为由键值对(Key=>Value)组成的文档, 类似于JSON对象, 字段值可以包含其他文档, 数组及文档数组.
数据库
MongoDB默认使用test
数据库, MongoDB可以建立多个数据库, 每一个都有自己的集合和权限.
可以使用show dbs命令显示所有数据库列表.
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
执行db命令显示当前的数据库对象或集合, 使用use命令连接到一个指定的数据库.
> db
test
> use local
switched to db local
> db
local
数据库名称命名规范
- 不能是空字符串(“”)。
- 不得含有
' '(空格)
、.
、$
、/
、\
和\0
(空字符)。 - 应全部小写。
- 最多64字节。
文档
文档由一组键值对(key-value)
组成(即BSON
).
MongoDB的特点就是文档不需要设置相同的字段, 并且相同的字段不需要相同的数据类型.
需要注意的是:
- 文档中的键/值对是有序的
- 文档中的值不仅可以是在双引号里的字符串, 还可以是其它几种数据类型, 也可以是嵌入整个文档
- MongoDB区分类型和大小写
- MongoDB的文档不能有重复的键
- 文档的键是字符串
集合
集合就是MongoDB文档组, 想到与关系数据库中的表格.
集合存在于数据库中, 没有固定的结构.
对集合可以插入不同格式的数据和类型. 但通常情况下具有一定关联性.
{"name": "Jack" }
{"name": "Mike", "age": 20}
{"name": "Steve", "age": 18, "sex": "male"}
MongoDB数据类型
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(true/false)。 |
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基础操作
创建数据库
使用use database_name
创建数据库, 如果数据库不存在, 则创建数据库, 否则切换到指定数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use student
switched to db student
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.student.insertOne({"name": "zhangsan"})
{
"acknowledged" : true,
"insertedId" : ObjectId("6454d4f7a4db8e3c7a63cd35")
}
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
student 0.000GB
在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
删除数据库
使用db.dropDatabase()
删除当前的数据库
> use student
switched to db student
> db.dropDatabase()
{ "dropped" : "student", "ok" : 1 }
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
创建集合
使用db.createCollection()
方法来创建集合
> use jxgl
switched to db jxgl
> db.createCollection("student")
{ "ok" : 1 }
> show collections
student
当插入一些文档时, mongoDB会自动创建集合
> db.course.insert({"name": "Java"},{"name": "Python"})
WriteResult({ "nInserted" : 1 })
> show collections
course
student
删除集合
使用db.collection.drop()
方法删除集合
> show collections
course
student
> db.course.drop()
true
> show collections
student
插入文档
db.collection.insertOne()
插入一条文档数据
> db.scores.insertOne({
... stuname: "zhangsan",
... coursename: "Java",
... score: 70})
{
"acknowledged" : true,
"insertedId" : ObjectId("6454dd9da4db8e3c7a63cd37")
}
> db.scores.find()
{ "_id" : ObjectId("6454dd9da4db8e3c7a63cd37"), "stuname" : "zhangsan", "coursename" : "Java", "score" : 70 }
db.collection.insertMany()
插入多条文档数据
> db.student.insertMany([{name: "lisi", gender: "female"}, {name: "wangwu", gender: "male", age: 18}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("6454de8aa4db8e3c7a63cd38"),
ObjectId("6454de8aa4db8e3c7a63cd39")
]
}
> db.student.find()
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd38"), "name" : "lisi", "gender" : "female" }
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd39"), "name" : "wangwu", "gender" : "male", "age" : 18 }
- 将文档定义为变量并插入
> document = ({name: "Jack", gender: "female"})
{ "name" : "Jack", "gender" : "female" }
> db.student.insert(document)
WriteResult({ "nInserted" : 1 })
> db.student.find()
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd38"), "name" : "lisi", "gender" : "female" }
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd39"), "name" : "wangwu", "gender" : "male", "age" : 18 }
{ "_id" : ObjectId("6454e533a4db8e3c7a63cd3a"), "name" : "Jack", "gender" : "female" }
更新文档
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>
}
)
- query: update的查询条件, 类似于关系数据库查询语句中where条件
- update: update的对象和一些更新的操作符(如$, $inc…), 类似于关系数据库set后的内容
- upsert: 如果不存在update的记录, 是否插入新的记录. 默认为false, 不插入
- multi: 是否将按条件查出来的多条记录全部更新. 默认为false, 只更新找到的第一条记录
> db.student.update({name: "lisi"}, {$set: {age: 19}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd38"), "name" : "lisi", "gender" : "female", "age" : 19 }
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd39"), "name" : "wangwu", "gender" : "male", "age" : 18 }
{ "_id" : ObjectId("6454e533a4db8e3c7a63cd3a"), "name" : "Jack", "gender" : "female" }
使用save()
方法通过传入的文档来替换已有的文档, _id主键存在就更新, 不存在就插入
> document = [{name: "Mike", gender: "female"}, {name: "Jorn", age: 19}]
[
{
"name" : "Mike",
"gender" : "female"
},
{
"name" : "Jorn",
"age" : 19
}
]
> db.student.save(document)
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
> db.student.find()
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd38"), "name" : "lisi", "gender" : "female", "age" : 19 }
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd39"), "name" : "wangwu", "gender" : "male", "age" : 18 }
{ "_id" : ObjectId("6454e533a4db8e3c7a63cd3a"), "name" : "Jack", "gender" : "female" }
{ "_id" : ObjectId("6454ecc4a4db8e3c7a63cd3c"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454ecc4a4db8e3c7a63cd3d"), "name" : "Jorn", "age" : 19 }
删除文档
在MongoDB中, 使用remove()
方法移出集合中的数据
db.collection.remove(
<query>,
{
justOne: <boolean>
}
)
- query: 删除文档的条件
- justOne: 默认为false, 删除所有匹配条件的文档; 设为true时, 只删除一个文档
> db.student.remove({gender: "female"})
WriteResult({ "nRemoved" : 3 })
> db.student.find()
{ "_id" : ObjectId("6454de8aa4db8e3c7a63cd39"), "name" : "wangwu", "gender" : "male", "age" : 18 }
{ "_id" : ObjectId("6454ecc4a4db8e3c7a63cd3d"), "name" : "Jorn", "age" : 19 }
查询文档
使用find()
方法以非结构化的方式显示所有文档, 可以使用pretty()
方法以易读的方式显示文档.
> db.student.find({gender: "female"})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd44"), "name" : "lisi", "gender" : "female" }
> db.student.find({gender: "female"}).pretty()
{
"_id" : ObjectId("6454f1daa4db8e3c7a63cd42"),
"name" : "Mike",
"gender" : "female"
}
{
"_id" : ObjectId("6454f200a4db8e3c7a63cd44"),
"name" : "lisi",
"gender" : "female"
}
MongoDB AND条件查询
MongoDB可以通过find()
方法传入多个以,
分割的键来实现AND条件查询.
以下示例类似于where 语句: where gender = ‘male’ and age = 18;
> db.student.find({gender: "male", age: 18}).pretty()
{
"_id" : ObjectId("6454f200a4db8e3c7a63cd45"),
"name" : "wangwu",
"gender" : "male",
"age" : 18
}
MongoDB OR条件查询
MongoDB 使用关键字$or
实现OR查询语句.
以下示例类似于: where gender = ‘female’ or age = 18;
> db.student.find({$or: [{gender: "female"}, {age: 18}]}).pretty()
{
"_id" : ObjectId("6454f1daa4db8e3c7a63cd42"),
"name" : "Mike",
"gender" : "female"
}
{
"_id" : ObjectId("6454f200a4db8e3c7a63cd44"),
"name" : "lisi",
"gender" : "female"
}
{
"_id" : ObjectId("6454f200a4db8e3c7a63cd45"),
"name" : "wangwu",
"gender" : "male",
"age" : 18
}
MongoDB条件操作符
操作 | 格式 |
---|---|
等于 | {<key>:<value>} |
小于 less than | {<key>:{$lt:<value>}} |
小于或等于 less than or equal | {<key>:{$lte:<value>}} |
大于 greater than | {<key>:{$gt:<value>}} |
大于或等于 greater than or equal | {<key>:{$gte:<value>}} |
不等于 not equal | {<key>:{$ne:<value>}} |
MongoDB小于操作符
MongoDB小于操作符使用$lt
关键字来实现, 返回所有age字段值小于19的文档.
> db.student.find({age: {$lt: 19}})
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
MongoDB小于等于操作符
MongoDB小于等于操作符使用$lte
关键字来实现, 返回所有age字段值小于等于19的文档.
> db.student.find({age: {$lte: 19}})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
MongoDB大于操作符
MongoDB大于操作符使用$gt
关键字来实现, 返回所有age字段值大于18的文档.
> db.student.find({age: {$gt: 18}})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
MongoDB大于等于操作符
MongoDB大于等于操作符使用$gte
关键字来实现, 返回所有age字段值大于等于18的文档.
> db.student.find({age: {$gte: 18}})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
MongoDB不等于操作符
MongoDB不等于操作符使用$ne
关键字来实现, 返回所有age字段值不等于19的文档.
> db.student.find({age: {$ne: 19}})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd44"), "name" : "lisi", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
同时使用$lt
和$gt
操作符
返回所有age 大于15 和age小于20的文档
> db.student.find({age: {$gt: 15, $lt: 20}})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
MongoDB Limit与Skip方法
MongoDB支持用limit()
方法接收数字参数, 以指定从文档中读取记录的条数
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
> db.student.find()
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd44"), "name" : "lisi", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
> db.student.find().limit(2)
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
使用skip()
方法接收数字参数, 跳过指定条数的文档记录. 例如以下示例显示从第二条数据开始的记录
> db.student.find().skip(1)
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd44"), "name" : "lisi", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
MongoDB排序
在MongoDB中使用sort()
方法对数据进行排序, 可以通过参数指定排序的字段, 并使用-1
和1
指定排序的方式. 其中1
为升序
排序, -1
为降序
排序.
> db.student.find().sort({age:-1})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd44"), "name" : "lisi", "gender" : "female" }
MongoDB索引的使用
除了上述的分页和排序功能,MongoDB还支持使用索引来优化查询性能。索引是一种用于加快数据库查询速度的数据结构,可以让数据库在执行查询时更快地定位到需要查询的数据。
创建索引
在MongoDB中,可以通过createIndex()
方法来创建索引。例如下面的例子中,为student
集合的name
字段创建索引:
> db.student.createIndex({name:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
在上面的例子中,{name:1}
表示对name
字段进行升序排序。如果要对name
字段进行降序排序,可以将参数设置为{name:-1}
。
查询优化
当我们执行查询操作时,如果查询条件匹配了索引,则MongoDB可以直接从索引中读取相关的数据,而无需扫描整个集合。这样就可以大大提高查询效率并减少查询时间。
例如下面的例子中,在student
集合中查找名字为Mike
的学生:
> db.student.find({name:"Mike"})
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
如果我们为name
字段创建了索引,那么MongoDB就可以直接从索引中获取name
等于Mike
的记录,而无需扫描整个集合。
删除索引
如果不再需要某个索引,可以使用dropIndex()
方法将其删除。例如下面的例子中,我们删除了student
集合中的name
索引:
> db.student.dropIndex({name:1})
{ "nIndexesWas" : 2, "ok" : 1 }
上面的例子中,{name:1}
指定了需要删除的索引。
MongoDB聚合方法
MongoDB的聚合方法是一种用于对文档进行聚合操作的查询方式,可以根据不同的条件进行分组、过滤、计数等操作。MongoDB中聚合的方法使用aggregate()
。
$match
方法
$match
方法可以用于筛选符合指定条件的文档,类似于SQL中的WHERE
语句。例如下面的例子中,使用$match
方法查找年龄大于18岁的学生:
> db.student.aggregate([
... {$match:{age:{$gt:18}}}
... ])
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
上面的例子中,$gt
表示大于,因此查询结果只会返回年龄大于18岁的学生。
$group
方法
$group
方法可以用于对文档进行分组统计。例如下面的例子中,我们使用$group
方法按照gender
字段对学生进行分组,并计算每个分组中学生的数量:
> db.student.aggregate([
... {$group:{
... _id:"$gender",
... count:{$sum:1}
... }}
... ])
{ "_id" : null, "count" : 1 }
{ "_id" : "male", "count" : 1 }
{ "_id" : "female", "count" : 2 }
上面的例子中,_id:"$gender"
表示按照gender
字段进行分组,count:{$sum:1}
表示统计每个分组中的记录数量。
$project
方法
$project
方法可以用于对文档进行投影操作,即从原始文档中提取需要的字段。例如下面的例子中,我们使用$project
方法只返回学生的姓名和年龄信息:
> db.student.aggregate([
... {$project:{
... _id:0,
... name:1,
... age:1
... }}
... ])
{ "name" : "Mike" }
{ "name" : "Jorn", "age" : 19 }
{ "name" : "lisi" }
{ "name" : "wangwu", "age" : 18 }
上面的例子中,_id:0
表示不返回默认的_id
字段,name:1
和age:1
表示只返回name
和age
字段。
$sort
方法
$sort
方法可以用于对文档进行排序。例如下面的例子中,我们使用$sort
方法对学生按照年龄进行升序排序:
> db.student.aggregate([
... {$sort:{age:1}}
... ])
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd42"), "name" : "Mike", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd44"), "name" : "lisi", "gender" : "female" }
{ "_id" : ObjectId("6454f200a4db8e3c7a63cd45"), "name" : "wangwu", "gender" : "male", "age" : 18 }
{ "_id" : ObjectId("6454f1daa4db8e3c7a63cd43"), "name" : "Jorn", "age" : 19 }
上面的例子中,age:1
表示按照年龄升序排序。
$sum
方法
$sum
方法可以用于对文档中的数值字段进行求和操作。例如下面的例子中,我们使用$sum
方法计算所有学生的年龄之和:
> db.student.aggregate([
... {$group:{
... _id:null,
... total_age:{$sum:"$age"}
... }}
... ])
{ "_id" : null, "total_age" : 37 }
上面的例子中,_id:null
表示不按照任何字段进行分组,total_age:{$sum:"$age"}
表示计算所有学生的年龄之和,并将结果存储在total_age
字段中。
$avg
方法
$avg
方法可以用于对文档中的数值字段进行平均值计算。例如下面的例子中,我们使用$avg
方法计算所有学生的年龄平均值:
> db.student.aggregate([
... {$group:{
... _id:null,
... avg_age:{$avg:"$age"}
... }}
... ])
{ "_id" : null, "avg_age" : 18.5 }
上面的例子中,_id:null
表示不按照任何字段进行分组,avg_age:{$avg:"$age"}
表示计算所有学生的年龄平均值,并将结果存储在avg_age
字段中。
$max
方法
$max
方法可以用于获取文档中某个字段的最大值。例如下面的例子中,我们使用$max
方法查找所有学生中年龄最大的那个人:
> db.student.aggregate([
... {$sort:{age:-1}},
... {$limit:1},
... {$project:{_id:0, name:1, age:1}}
... ])
{ "name" : "Jorn", "age" : 19 }
上面的例子中,我们首先使用$sort
方法按照年龄降序排序,然后使用$limit
方法限制查询结果只返回第一条记录,最后使用$project
方法只返回姓名和年龄字段。
$min
方法
$min
方法可以用于获取文档中某个字段的最小值。例如下面的例子中,我们使用$min
方法查找所有学生中年龄最小的那个人:
> db.student.aggregate([
... { $match: { age: { $exists: true } } }, // 只选择具有age字段的文档
... { $sort: { age: 1 } }, // 按年龄升序排序
... { $limit: 1 }, // 获取前1个文档(即最小年龄的学生)
... { $project: { _id: 0, name: 1, age: { $ifNull: ['$age', Number.MAX_SAFE_INTEGER] } } } // 只保留name和age字段,并用ifNull函数处理缺失的age字段
... ])
{ "name" : "wangwu", "age" : 18 }
上面的例子中,我们首先使用$sort
方法按照年龄升序排序,然后使用$limit
方法限制查询结果只返回第一条记录,最后使用$project
方法只返回姓名和年龄字段。