Appearance
数据模型
MongoDB对于文档的格式并没有强制性的要求, 但不等于我们不能在文档中表达数据的关系 在MongoDB中我们可以通过'内嵌式结构'和'规范式结构'来表达文档之间的关系
内嵌式结构
在文档中又包含一个文档,我们就称之为内嵌式的结构
{
name:'zs',
age:'18',
card:{
num:'420626200002023556',
date: 88
}
}
一对一
一个人有一张身份证
1.1内嵌式结构
db.person.insert({
name:'zs',
age:'18',
card:{
num:'420626200002023556',
date: 88
}
})
db.person.find({name:'zs'})
- 优势: 一次查询就能得到所有数据
- 劣势: 如果数据比较复杂, 不方便管理和更新
- 应用场景: 数据不复杂/查询频率较高数据
一对多
一个人有多本书
db.person.insert({
name:'zs',
age:'18',
books:[{
name:'玩转HTML',
price: 88
},
{
name:'玩转CSS',
price: 88
}]
})
db.person.find({name:'zs'})
- 优势: 一次查询就能得到所有数据
- 劣势: 冗余数据较多, 不方便管理和更新
- 应用场景: 数据不复杂/查询频率较高数据
多对多
一个学生有多个老师, 一个老师有多个学生
db.students.insert([{name:'zs', teachers:[{name:'it666'}, {name:'itzb'}]},
{name:'ls', teachers:[{name:'it666'}, {name:'itzb'}]}])
db.teachers.insert([{name:'it666', students:[{name:'zs'}, {name:'ls'}]},
{name:'itzb', students:[{name:'zs'}, {name:'ls'}]}])
db.students.find({name:'zs'})
db.teachers.find({name:'itzb'})
- 优势: 一次查询就能得到所有数据
- 劣势: 冗余数据较多, 更新和管理较为复杂
- 应用场景: 数据比较简单/查询频率较高数据
规范是结构
将文档存储在不同的集合中, 然后通过某一个字段来建立文档之间的关系, 我们就称之为规范式
{
_id: 1,
num:'420626200002023556',
date: 88
}
{
name:'zs',
age:'18',
cardId: 1
}
一对一
一个人有一张身份证
db.card.insert({
_id: 123,
num:'420626200002023556',
date: '2022-12-08',
userId: 456
})
db.person.insert({
_id: 456,
name:'zs',
age:'18',
cardId: 123
})
## 聚合查询
db.person.aggregate([
{$lookup:{
from: 'card',
localField: 'cardId',
foreignField: '_id',
as: 'card'
}}
])
- 优势: 如果数据比较复杂, 也方便管理和更新
- 劣势: 查询数据相对内嵌结果稍微有点复杂
- 应用场景: 数据比较复杂/更新频率较高数据
一对多
一个人有多本书
db.books.insert([{
_id: 1,
name:'玩转HTML',
price: 88,
userId:123
},
{
_id: 2,
name:'玩转CSS',
price: 88,
userId:123
}])
db.person.insert({
_id: 123,
name:'ls',
age:'20',
booksId:[1, 2]
})
## 聚合查询
db.person.aggregate([
{$lookup:{
from: 'books',
localField: 'booksId',
foreignField: '_id',
as: 'books'
}}
])
- 优势: 冗余数据较少, 更新较为方便
- 劣势: 查询数据相对内嵌结果稍微有点复杂
- 应用场景: 数据比较复杂/更新频率较高数据
多对多
一个学生有多个老师, 一个老师有多个学生
db.students.insert([{_id:1, name:'zs'},{_id:2, name:'ls'}])
db.teachers.insert([{_id:3, name:'it6666'},{_id:4, name:'itzb'}])
db.relation.insert([{stuId:1, teacherId:3},{stuId:1, teacherId:4},{stuId:2, teacherId:3},{stuId:2, teacherId:4}])
## 聚合操作
db.students.aggregate([
{$lookup:{
from: 'relation',
localField: '_id',
foreignField:'stuId',
as: 'relation'
}},
{$lookup:{
from: 'teachers',
localField: 'relation.teacherId',
foreignField:'_id',
as: 'teachers'
}},
{$project:{_id:0, name:1, teachers:1}}
])
- 优势: 冗余数据较少, 更新较为方便
- 劣势: 查询数据相对内嵌结果稍微有点复杂
- 应用场景: 数据比较复杂/更新频率较高数据
树形结构
在MongoDB中我们除了可以使用'内嵌式结构'和'规范式结构'来表示数据的关系以外
由于MongoDB数据的灵活性, 我们还可以使用'树形结构'来表示数据之间的关系
什么是树形结构
Database
|
|--------------------|
Relational No-Relational
| |-----------|-------------|
MySQL Key-Value Document
| |
Redis MongoDB
对于经常需要查询子节点的数据
{name:'Database', parent:null}
{name:'No-Relational', parent:'Database'}
{name:'Document', parent:'No-Relational'}
{name:'MongoDB', parent:'Document'}
{name:'Key-Value', parent:'No-Relational'}
{name:'Redis', parent:'Key-Value'}
例如:我们要查询非关系型数据库有几种类型, 我们可以使用find({parent:'No-Relational'})
对于经常需要查询父节点的数据
{name:'Database', children:['Relational', 'No-Relational']}
{name:'No-Relational', children:['Key-Value', 'Document']}
{name:'Document', children:['MongoDB']}
{name:'MongoDB', children:[]}
例如:我们要查询MongoDB是什么类型的的数据, 我们可以使用find({children:{$in:['MongoDB']}})
对于经常查询祖先或者后代节点的数据
{name:'Database', ancestors:[]}
{name:'No-Relational', ancestors:['Database']}
{name:'Document', ancestors:['Database', 'No-Relational']}
{name:'MongoDB', ancestors:['Database', 'No-Relational', 'Document']}
例如: 我们要查询MongoDB的祖先有哪些, 我们可以使用find({name:'MongoDB'})
例如: 我们要查询Database的后代有哪些, 我们可以使用find({ancestors:{$in:['Database']}}})