MongoDB 基础
开始讲解MongoDB基础操作之前,先了解下SQL 与 MongoDB 常见术语对比
SQL 与 MongoDB 常见术语对比
MongoDB数据库
数据库用于存储所有集合,而集合又用于存储所有文档。一个 MongoDB 中可以创建多个数据库,每一个数据库都有自己的集合和权限。
MongoDB 预留了几个特殊的数据库。
admin : admin 数据库主要是保存 root 用户和角色。例如,system.users 表存储用户,system.roles 表存储角色。一般不建议用户直接操作这个数据库。将一个用户添加到这个数据库,且使它拥有 admin 库上的名为 dbAdminAnyDatabase 的角色权限,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如关闭服务器。
local : local 数据库是不会被复制到其他分片的,因此可以用来存储本地单台服务器的任意 collection。一般不建议用户直接使用 local 库存储任何数据,也不建议进行 CRUD 操作,因为数据无法被正常备份与恢复。
config : 当 MongoDB 使用分片设置时,config 数据库可用来保存分片的相关信息。
test : 默认创建的测试库,连接 mongod 服务时,如果不指定连接的具体数据库,默认就会连接到 test 数据库。
数据库名可以是满足以下条件的任意 UTF-8 字符串:
不能是空字符串
""
。不得含有
' '
(空格)、.
、$
、/
、\
和\0
(空字符)。应全部小写。
最多 64 字节。
数据库名最终会变成文件系统里的文件,这也就是有如此多限制的原因。
数据库操作
选择和创建数据库
连接mongodb数据库:
mongo
显示所有数据库:
show databases;
选择使用数据库:
use 数据库名;
删除数据库:
db.dropDatabase();
集合操作
集合类似与关系型数据库中的表
显示出所有集合
show tables
show collections
集合显式创建
db.createCollection(name)
# name为集合的名字
集合的命名规范
1、集合名不能是空字符串 "" 。
2、集合名不能含有 \0 字符(空字符 ) ,这个字符表示集合名的结尾。
3、集合名不能以 "system." 开头,这是为系统集合保留的前缀。
4、用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$ 。
集合的隐式创建
当向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合。 ::: tip 提示:通常使用隐式创建文档即可。 :::
集合的删除
db.集合名.drop()
::: tip 如果成功删除选定集合,则 drop() 方法返回 true ,否则返回 false 。 :::
文档基本CRUD
文档( document )的数据结构和 JSON 基本一样。 所有存储在集合中的数据都是 BSON 格式。
文档插入
(1)单个文档插入
使用insert()或save()方法向集合中插入文档
db.集合名.insert({"name":"张三","address":"湖北"})
::: tip
1、 集合如果不存在,则会隐式创建。
2、mongo 中的数字,默认情况下是 double 类型,如果要存整型,必须使用函数 NumberInt( 整型数字 ) ,否则取出来就有问题了。
3、插入当前日期使用 new Date()。
4、插入的数据没有指定 _id ,会自动生成主键值。
5、如果某字段没值,可以赋值为 null ,或不写该字段。
6、出现WriteResult({"nInserted":1})就代表添加成功。 :::
::: warning
1. 文档中的键 / 值对是有序的。
2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档 ) 。
3. MongoDB 区分类型和大小写。
4. MongoDB 的文档不能有重复的键。
5. 文档的键是字符串。除了少数例外情况,键可以使用任意 UTF-8 字符。
文档键命名规范:
键不能含有 \0 ( 空字符 ) 。这个字符用来表示键的结尾。
. 和 $ 有特别的意义,只有在特定环境下才能使用。
以下划线 "_" 开头的键是保留的 ( 不是严格要求的 ) 。 :::
批量插入
db.集合名.insertMany([{document1},{document2},{document3}...]);
::: tip 插入时指定了 _id ,则主键就是该值,如果没有指定,则自动生成。 如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚掉。 因为批量插入由于数据较多容易出现失败,因此,可以使用 try catch 进行异常捕捉处理,测试的时候可以不处理。
try {db.集合名.insertMany([{document1},{document2},{document3}...]);} catch (e) {print (e);}
:::
文档的更新
db.集合名.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
(1)覆盖的修改
如果我们想修改name为张三,地址改为河南, 输入以下语句
db.集合名.update({"name":"张三"},{"address":'河南'})
修改之后,发现除了address字段,其他属性全部没有了,这是因为修改覆盖了原有的数据,没有填写值默认为空了。
(2)局部修改
为了解决上面的问题,我们需要使用修改器 $set 来实现,命令如下:
db.集合名.update({"name":"王五"},{$set:{name:'张三',age:23,address:'河南'}})
(3)批量修改
更新所有名叫张三的,修改地址为北京
//默认只修改第一条数据
db.集合名.update({"name":"张三"},{$set:{"address":"北京"}})
//修改所有符合条件的数据
db.集合名.update({"name":"张三"},{$set:{"address":"北京"}},{multi:true})
提示:如果不加后面的参数,则只更新符合条件的第一条记录。
(4)列值增长的修改
如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用 $inc 运算符来实现。
现在我们需要将名叫赵四的年龄增长1岁,命令如下:
db.mymogodb.update({name:"赵四"},{$inc:{age:1}})
删除文档
删除文档的语法结构
db.集合名.remove(
<query>,
<justOne>
)
如果你的 MongoDB 是 2.6 版本以后的,语法格式如下:
db.集合名.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
(1)全部删除
db.集合名.remove({})
(2)删除指定数据
删除_id为646c4ab6bb1f1832a1ac7277的数据
db.集合名.remove({_id:ObjectId("646c4ab6bb1f1832a1ac7277")})
基本查询
查询数据的语法格式如下:
db.集合名.find(<query>,[projection])
(1)查询所有
db.集合名.find().pretty()
# pretty() 方法以格式化的方式来显示所有文档。
(2)指定查询
会发现每条文档会有一个叫 _id 的字段,这个相当于我们原来关系数据库中表的主键,当你在插入文档记录时没有指定该字段, MongoDB会自动创建,其类型是 ObjectID 类型。
如果我们在插入文档记录型。时指定该字段也可以,其类型可以是 ObjectID 类型,也可以是 MongoDB 支持的任意类
比如我想查询 名字 为 张三 的记录,怎么办,很简单!只要在 fifind() 中添加参数即可,参数也是 json 格式,如下:
db.集合名.find({"name":"张三"})
如果你只需要返回符合条件的第一条数据,我们可以使用 fifindOne 命令来实现,语法和 find 一样。
(3)投影查询(projection Query)
如果要查询结果返回部分字段,则需要使用投影查询(不显示所有字段,只显示指定的字段)。
如:查询结果只显示 _id 、 name 、age :
db.集合名.find({条件}, { field1: 1, field2: 1, _id: 0 })
# 1 表示要包括该字段,而 0 表示要排除该字段
统计查询
db.集合名.count(query, options)
(1)统计所有记录数
db.集合名.count()
(2)按条件统计记录数
db.集合名.count({age:25})
排序查询
sort() 方法对数据进行排序, sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式
其中 1 为升序排列,而 -1 是用 于降序排列。
db.集合名.find().sort(排序方式)
::: tip skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip() ,最后是显示的 limit() ,和命令编写顺序无关。 :::
正则的复杂条件查询
MongoDB 的模糊查询是通过 正则表达式 的方式实现的。格式为:
db.集合名.find({field:/正则表达式/})或db.集合.find({字段:/正则表达式/})
提示:正则表达式是 js 的语法,直接量的写法。 例如,我要查询name包含“宋 ” 的所有文档,代码如下:
db.集合名.find({name:/宋/})
如果要查询name的内容中以“张”开头的
db.集合名.find({name:/^张/})
比较查询
<, <=, >, >= 这个操作符也是很常用的,格式如下 :
db.集合名.find({ "field" : { $gt: value }}) // 大于: field > value
db.集合名.find({ "field" : { $lt: value }}) // 小于: field < value
db.集合名.find({ "field" : { $gte: value }}) // 大于等于: field >= value
db.集合名.find({ "field" : { $lte: value }}) // 小于等于: field <= value
db.集合名.find({ "field" : { $ne: value }}) // 不等于: field != value
查询age大于 20 的记录
db.集合名.find({age:{$gt:30}})
包含查询
包含使用 $in 操作符。 示例:查询数据的集合中 name 字段包含宋江 或张飞 的文档
db.集合名.find({name:{$in:['宋江','张飞']}})
条件连接查询
我们如果需要查询同时满足两个以上条件,需要使用 $and 操作符将条件进行关联。(相 当于 SQL 的 and ) 格式为:
$and:[ { },{ },{ } ]
示例:查询评论集合中 age 大于等于20 并且小于35 的文档:
db.集合名.find({$and:[{age:{$gte:20}},{age:{$lt:35}}]})
如果两个以上条件之间是或者的关系,我们使用 操作符进行关联,与前面 and的使用方式相同
查询评论集合中name 姓张 ,或者age小于30 的文档记录
db.集合名.find({$or:[{name:/^张/},{age:{$lt:30}}]})
分页查询
可以使用 limit() 方法来读取指定数量的数据,使用 skip() 方法来跳过指定数量的数据。
基本语法如下所示:
db.集合名.find().limit(NUMBER).skip(NUMBER)
如果你想返回指定条数的记录,可以在 find 方法后调用 limit 来返回结果 (TopN) ,默认值 20 ,例如:
db.集合名.find().limit(3)
skip方法同样接受一个数字参数作为跳过的记录条数。(前N个不要),默认值是0。
db.集合名.find().skip(3)
聚合查询
聚合的方法使用aggregate();
db.集合名.aggregate(AGGREGATE_OPERATION)
db.集合名.aggregate([{$group : {_id : "$address", num_tutorial : {$sum : 1}}}])
# 以上示例类似sql语句
select address, count(*) from mycol group by address;
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。 表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。 聚合框架中常用的几个操作:
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。
- 感谢你赐予我前进的力量