RDBMS(Relational Database Management System):
关系型数据库.
MongoDB属于文档数据库
MongoDB的数据模型是面向文档的,所谓文档是一种类似于JSON的结构,简单理解MongoDB这个数据库中存的是各种各样的JSON(BSON)
BSON
中的B
为Binary
就是说这其实是一个二进制的JSON文件
- 数据库(database)数据库是一个仓库,在仓库中可以存放集合。
- 集合(collection)集合类似于数组,在集合中可以存放文档。
- 文档(document)文档数据库中的最小单位,我们存储和操作的内容都是文档。
展示数据库
1 | show dbs |
进入数据库
1 | use test |
注意:在mongo中,数据库和集合都不需要手动创建.
当我们创建文档时,如果文档所在的集合或数据库不存在会自动创建数据和集合
1 | # 查看数据库的集合(很想MySQL的show tables) |
SQL术语 | MongoDB术语 | 解释说明 |
---|---|---|
database | database | 数据库 |
table | collecion | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id设置为主键 |
文档:
{name:“张三”,age:20,hobby:{“看书”,“旅游”,“唱歌”}}
注意:
- 文档中的键/值对是有序的。
- 文档的键必须是字符串
如果将文档类比成数据库中的行,那么集合就可以类比成数据库的表
在mongodb中的集合是无模式的,也就是说集合中存储的文档的结构可以是不同的,比如下面的两个文档可以同时存入到一个集合中:
{“name”:”hyl”}
{“name”:”hyl”,”age”:1}
Type | Number | String | Notes |
---|---|---|---|
Double | 1 | “double” | —– |
字符串 | 2 | “string” | —– |
对象 | 3 | “object” | —– |
数组 | 4 | “array” | —– |
二进制数据 | 5 | “binData” | —– |
未定义 | 6 | “undefined” | 已过期 |
ObjectId | 7 | “objectId” | —– |
Boolean | 8 | “bool” | —– |
日期 | 9 | “date” | —– |
空 | 10 | “null” | —– |
正则表达式 | 11 | “regex” | —– |
DBPointer | 12 | “dbPointer” | 已过期 |
JavaScript(代码) | 13 | “javascript” | 此数据类型用于将JavaScript代码存储到文档中 |
符号 | 14 | “symbol” | 已过期 |
JavaScript(带范围) | 15 | “javascriptWithScope” | —– |
32位整数 | 16 | “int” | —– |
时间戳 | 17 | “timestamp” | —– |
64位整数 | 18 | “long” | —– |
Decimal128 | 19 | “decimal” | New in version 3.4 |
Min key | -1 | “minKey” | —– |
Max key | 127 | “maxKey” | —– |
操作mongoDB数据库
创建数据库:
如果数据库不存在则创建数据库,否则切换到指定的数据库1
use 数据库名
查看所有数据库:
1
show dbs
注意:刚创建的数据库是不能显示的.必须插入数据库才能显示
查看当前正在使用的数据库
1
db
或:
1
db.getName()
删除数据库:
1
db.dropDatabase()
插入数据
1
db.student.insert({name:"hyl",age:18,gender:1,address:"北京"})
断开连接:
1
exit
操作集合
查看当前数据库下有哪些集合
1
show collections
创建集合
1
db.createCollection("集合名")
或者:
创建一个空的集合并添加一个文档1
db.集合名.insert(document)
删除当前数据库中的集合
1
db.集合名.drop(document)
操作文档
插入文件
使用 insert()方法插入文档
1
db.集合名.insert(document)
eg:
1
db.student.insert({name:"hyl",age:18,gender:1,address:"北京"})
如果要插入多条数据:
注意要添加中括号:1
2
3db.student.insert(
[{name:"hyl",age:18,gender:1,address:"北京"},
{name:"dsz",age:15,gender:0,address:"广州"},])使用save方法插入文档:
1
db.集合名.save(文档)
如果不指定_id字段,save()方法类似于 Insert()方法.如果指定_id字段,则会更新_id字段的数据.
1
2db.student.save(
{name:"hyl",age:18,gender:1,address:"北京"})1
2
3db.student.save(
{_id:ObjectId(5995096201 723fe2a0d8d17"},name:"poi",age:22,gender:7 address:"石家庄",isDelete:e}
)
文档更新:
update()方法用于更新已经存在的文档
1
2
3
4
5
6
7
8
9db.集合名.update(
query,
update,
{
upset:<boolean>,
multi:<boolean>,
writeConcern:<document>
}
)参数说明:
- query:
updata的查询条件,类似于sql里的update语句内where后面的内容. - update:
update的对象和一些更新的操作符($set,$inc)等 - upset:
可选.如果不存在update的记录,是否当成新数据插入,true为插入,False为不插入(默认False) - multi:
可选.如果查找到多条数据,是否更新全部数据,否则只更新一条数据(默认False) - writeConcern:
可选,抛出异常的级别.
- query:
1 | // 示例:将李雷的年龄更新为25 |
删除集合的某个文档:$unset
1 | db.student.update({name:"lilei"},{$unset:{age:25}}) |
save()方法通过传入的文档替换已有文档:
1
2
3
4
5
6db.集合名.save(
document,
{
writeConcern:<document>
}
)
文档删除
说明:在执行 remove()函数前,先执行find命令来判断执行的条件是否存在是一个良好习惯
1
2
3
4
5
6
7db.集合名.remove(
query,
{
justOne:<boolean>,
writeConcern:<document>
}
)- query:
可选,删除文档的条件 - justOne:
可选,如果为tureen或1,则只删除一个文档 - writeConcern:
可选,抛出异常的级别.
- query:
eg:删除名字为tom的学生
1
2
3db.student.remove({name:"tom"})
db.student.remove({name:"tom"},{justOne:"true"})
文档查询:
find()方法:
1
2
3
4// 查询集合下所有的文档
db.集合名.find()
db.student.find()1
2
3
4
5
6
7
8
9
10
11// 查询指定列
db.集合名.find(
query,
{
<key>:1,
<key>:1
}
)
// 查看年龄为18的所有人的姓名,性别:
db.student.find({age:18},{name:1,age:1})query:查询条件
key:要显示的字段,1表示显示pretty()方法以格式化的方式来显示文档
1
bd.student.find().pretty()
findOne():方法查询匹配结果哦第一条数据
1
db.student.findOne({gender:0})
查询条件操作符:
$gt
,$gte
,$lt
,$lte
:大于,大于等于,小于,小于等于.1
2
3
4db.集合名.find(<key>:{$gt:<value>})
// 查询年龄大于20的学生
db.student.find({age:{$gt:20}})1
2// 查询年龄大于20,小于40的学生
db.student.find({age:{$gte:20,$lte:40}})等于使用冒号
:
1
db.student.findOne({gender:0})
使用id进行查询:
1
db.student.find({"_id":ObjectId("59995084b019723fe2a0d8d14")})
id查询某个结果集的数据条数
1
db.student.find().count()
查询某个字段的值当中是否包含另一个值
1
2// 查询名字包含yl的学生
db.student.find({name:/yl/})ObjectId()查询某个字段的值是否以另一个值开头
1
2// 查询名字以h开头的学生
db.student.find({name:/^h/})
and,or:
1
2
3db.集合名.find(条件1,条件2,条件3....)
db.student.find({age:{$gt:16},gender:0})1
2
3
4
5db.集合名.find({
$or:[{条件1},{条件2},{条件3}....]
})
db.student.find({$or:[{age:{$gt:16}},{gender:0}]})1
2
3
4
5db.集合名.find({
条件1,
条件2,
$or:[{条件3},{条件4}]
})limit,skip:
limit():读取指定数量的数据记录
1
db.student.find().limit(2)
skip():跳过指定数量的数据
1
2// 跳过前三条
db.student.find().skip(3)limit与skip联合使用:
实现分页功能1
db.student.find().skip(3).limit(2)
排序:
1
db.集合名.find().sort(<key>:1|-1)
1表示升序,-1表示降序
1
db.student.find().sort(age:1)
练习:
1 | # 进入my_test效据库 |
MongoDB支持直接通过内嵌文档的属性进行查询.使用点号获取.
但是注意,此时的属性名必须使用引号
db.users.update({username:sunwukong},{$set:hobby:{cities:["beijing","shanghai","shenzhen"],movies:["sangu","hero"]})
db.users.find({hobby.movies:'hero'})
是错的.
必须使用db.users.find({"hobby.movies":'hero'})
发现movies其实是一个数组.所以说,MongoDB还支持数组的匹配
$push
用于向数组中添加一个新的元素
db.users.update({username:'tangseng'},{$set:{hobby:{movies:["A Chinese odyssey","King of comedy"]} )
db.users.update({username:'tangseng'},{$push:{"hobby.movies":'teretellar'}})
还可以使用
$addToSet
,有点类似于Redis的msetnx
,如果数组中已经存在了该元素,则添加失败
注意查询集可以使用skip()和limit()
配合使用:
skip((页码-1)*每页显示的条数).limit(每页显示的条数)
MongoDB会自动调整
limit
和skip
的位置,所以写成.skip().limit()
也行
文档间的关系
- 一对一
- 一对多
- 多对多
MongoDB可以通过内嵌文档的形式来体现出一对一的关系
1 | db.person.insert({ |
一对多也可以使用内嵌文档的形式表示:
只要将内嵌文档的字典改为列表即可
1 | db.artcile.insert({ |
和MySQL类似,MongoDB一对多关系也可以拆成两张表:
1 | db.artcile.insert({ |
那么拆成两个集合如何查找?
查找标题为XXX的文章对应的回复:
1 | var replyid = db.artcile.findOne({title:'XXX'})._id; |
这种查找方式很像Django里的ORM的会造成1+N问题的查找方式
多对多的关系在MongoDB中还是以两张表的形式
1 | db.terchers.insert([ |
练习:
现在有两个JSON文件dept.json
和emp.json
(部门和员工)
1 | # 查均工资小于2000的员工 |
查均财务部的所有员工
var dept = db.dept.find({dname:'财务部'})[0].deptn
db.emp.find({depno:depto})
注意
db.dept.find({dname:'财务部'})
的查询结果是数组,要用[0]切出来或者直接使用
var dept = db.dept.findOne({dname:'财务部'}).deptn
排序
1 | # 主要关键字sal升序排列,次要关键字empno降序排列 |
limit,skip和sort可以任意顺序编写
投影:
1 | // 查询全部行 |
Mongoose:Node.js的MongoDB的模块
- 可以为文档创建一个模式结构(Schema)
- 可以对模型中的对象/文档进行验证
- 数据可以通过类型转换转换为对象模型
- 可以使用中间件来应用业务逻辑挂钩
- 比Node原生的MongoDB驱动更容易
mongoose中为我们提供了几个新的对象
- Schema(模式对象)
Schema对象定义约束了数据库中的文档结构 - ModeI
Mode对象作为集合中的所有文档的表示,相当于MongoDB数据库中的集合collection - Document
表示集合中的具体文档,相当于集合中的一个具体的文档
安装
1 | npm i mongoose --save |
导入:
1 | var mongoose = require('mongoose'); |
连接:
1 | Mongoose.connect('mongodb://localhost:27017/数据库',{useMongoClient:true}) |
监听数据库的连接:使用mongoose的connection属性
1 | // 数据库成功连接的事件 |
简单使用:
1 | var mongoose = require('mongoose'); |
Schema模式对象
1 | var mongoose = require('mongoose'); |
使用Model对数据库进行增删改查:
1 | var BlogModel = mongoose.model('Blog', blogSchema); |
通过find()查询的结果,返回的对象就是Document文档对象
有点类似于Django的Model,mongoose中的Document对象就是Model的实例
1 | // 修改 |
1 | // 删除 |
Count:
1 | // Model.count(conditions,[callback]) |
document
Document是Model的实例,和Django不同的是Model查询结果是查询集(queryset)
,mongoose通过Model查询的结果都是Document
1 | var mongoose = require('mongoose'); |
Document的方式:
- save
- equals(doc)
- id
- get(path,[type])
- set(path, value, [type])
- update(update, [options], [callback])
- save([callback])
- remove([callback])
- isNew
- isInit(path)
- toJSON()
- toObject():转化为普通的js对象
1 | // Model#save([options],[fn]) |
这种方法和DJango的Model操作及其相似,可以使用Model.create方法创建行,也可以使用document.save创建行
1 | StudentModel.findOne({},function (err,doc){ |