Mongodb / Mongoose
介绍
KUN Visual Novel
后端整体是采用 koa + mongodb
技术栈的,mongodb
是一个 NoSQL
数据库,与传统的 MySQL
和 PostgreSQL
可能有一些区别。
- 由于我们是
Nodejs
的后端,所以我们采用mongoose
来作为mongodb
的驱动,或许您可能了解ORM
,mongoose
就好比Hibernate
,MyBatis
之类的东东 - 在
mongodb
中,Collection
和Document
可以类比于关系型数据库中的Table
和Row
- 关于
Schema
,在mongodb
中Schema
是数据库中Collection
的结构描述,在mongoose
中,它是一层ORM
,mongoose
的schema
不仅用于描述数据模型的结构,还可以定义数据模型的方法、虚拟字段等。 - 关于
Model
,在mongodb
中Model
是Collection
的抽象,它允许应用程序执行数据库操作。由于mongoose
的缘故,使用mongoose.model
可以很方便的使用Model
与数据库进行交互,它通过定义Schema
和使用模型的方式,将应用程序中的数据映射到数据库文档。 - 关于数据库范式,由于这是
NoSQL
,所以关系范式没有啦。因此您可以看到我们的用户 Model 等完全不遵循关系数据库范式。
为什么要选 Mongodb
Mongodb 似乎非常适合论坛这种网站,只是听说
难道就我一个人觉得 Mongo
这个词很瑟琴吗
Mongodb
本项目中我们使用了 Mongodb
作为数据库,它是一个非关系型数据库
可以查看 Mongodb Documentation 来进行了解,这是良好的学习方式
Mongoose
本项目中我们使用了 Mongoose
来在 Nodejs 环境下操作 Mongodb
,官网(v8.0.3)的描述是
elegant mongodb object modeling for node.js
可以查看 Mongoose Documentation 来进行了解
使用
本项目中在 src/db/connection.ts
定义了 Mongodb
的连接
import mongoose from 'mongoose'
import env from '@/config/config.dev'
const DB_URL = `mongodb://${env.MONGO_USERNAME}:${env.MONGO_PASSWORD}@${env.MONGO_HOSTNAME}:${env.MONGO_PORT}/${env.DB_NAME}`
mongoose.connect(DB_URL)
export default mongoose
我们已经在根目录的 .env
文件中定义了所需的环境变量,我们这里将其参数(用户名、密码、HOST、PORT、数据库名)拼合在一起形成了一个 Mongodb
的地址,然后使用 Mongoose
来连接 Mongodb
Models
需要给 Mongoose
定义一层 Model
才能通过 Mongoose
将集合映射到数据库
大白话就是定义一个这样的数据结构,Mongoose
才能把数据写到数据库里
可以查看本项目 src/models
文件夹下,里面存放了所有的 model
Transaction
Transaction
是一个很重要的特性,在 mongodb
中同样存在 Transaction
,KUN Visual Novel
采用 mongoose
,会以如下方式使用 Transaction
// Start Transaction
const session = await mongoose.startSession()
session.startTransaction()
try {
...some operation
} catch (error) {
// If catch error, abort transaction
await session.abortTransaction()
session.endSession()
throw error
}
Trigger
在 mongodb
中,没有 trigger
,但是 KUN Visual Novel
借助 mongoose
的 pre-save
实现了类似的效果
// pre-save hook,increase nid before save document
NonMoeSchema.pre('save', increasingSequence('nid'))
Join
mongodb
中没有 join
,但是我们可以用类似的方法实现,例如 Embedded
, References
, Aggregation
,由于 KUN Visual Novel
未采用 _id
作为集合的唯一查询标识 (_id
是有的,只是没有用而已),因为我们觉得在浏览器地址栏输入 topics/1
或者 kungalgamer/1
,就能进入用户或者话题的主页是一件非常酷的事情,所以我们将每一个 Schema
都添加了一个字段 XXXid
,用来标识唯一性。因此我们无法使用 ref
来进行类似于 join
的操作,所以我们使用了 Virtual
来实现类似的操作。
// Create virtual 'users'
TopicSchema.virtual('user', {
ref: 'user',
localField: 'uid',
foreignField: 'uid',
})
使用的时候只需要
const topics = await TopicModel.find(query)
.sort(sortOptions)
.skip(skip)
.limit(limit)
.populate('user', 'uid avatar name')
.lean()