Midway-Mongoose实践

Table Of Content
前言
之前写了个Midway & Typescript & Mongoose的demo 但是呢 才发现从utils创建出来的model无法获取model中方法的 这就很尴尬了 第一版的逻辑是这样的
1.在utils
工具文件中暴露出一个getModel(mongoose: any, options: ISchemaOption)
方法 通过定义Schema设定来对应创建model并返回创建好的对象
// model/utils.ts
import { ISchemaOption } from "../interface";
export function getModel(mongoose: any, options: ISchemaOption) {
if(mongoose.models[options.modelName]){
return mongoose.models[options.modelName];
}
const Schema = mongoose.Schema
const schema = new Schema(options.schemaOptions)
return mongoose.model(options.modelName, schema, options.collection)
}
2.在对应model
文件中通过@plugin
来引入mongoose
传入引入的mongoose
调用上面一步创建好的getModel
方法 生成可操作数据库的model对象
// model/posts.ts
import { provide, plugin } from 'midway'
import { Mongoose } from 'mongoose';
import { getModel } from './utils';
const options = {
modelName: 'Posts',
collection: 'posts',
schemaOptions: {
title: String,
brief: String,
time: { type: Date , default: Date.now },
content: String,
count: Number,
isDelete: { type: Number , default: 0 }
}
}
@provide()
export class PostModel {
@plugin()
mongoose: Mongoose;
getModel() {
return getModel(this.mongoose, options)
}
}
然后问题就出来了Typescript
并没有检索出里面可以操作数据库的方法 -> 排查发现当时也并没有定义getModel
方法的返回类型 所以导致Typescript
没办法检索数据model里拥有的方法
分(chui)析(shui)
通过VS Code快捷键command + click可以进入到定义mongoose类型的源码里 这里就说一下我一顿瞎分析的步骤吧
1.进入到声明model
的地方 从声明中能看出来model的返回值是一个继承于Document
的Model
类型泛型 并且还有声明合并 推测是函数重载(?
// @types/mongoose/index.d.ts
/**
* Defines a model or retrieves it.
* Models defined on the mongoose instance are available to all connection
* created by the same mongoose instance.
* @param name model name
* @param collection (optional, induced from model name)
* @param skipInit whether to skip initialization (defaults to false)
*/
export function model<T extends Document>(name: string, schema?: Schema, collection?: string,
skipInit?: boolean): Model<T>;
export function model<T extends Document, U extends Model<T>>(
name: string,
schema?: Schema,
collection?: string,
skipInit?: boolean
): U;
2.进入到声明Model
的地方 发现它竟然是个any
??? 当时有点懵逼 难倒真的要Anyscript
了嘛 然后发现下面定义Model
的接口的地方是应该自己自定义的一个Document
泛型对象的 里面就包含着数据库操作的方法
// @types/mongoose/index.d.ts
/*
* section model.js
* http://mongoosejs.com/docs/api.html#model-js
*/
export var Model: Model<any>;
interface Model<T extends Document, QueryHelpers = {}> extends NodeJS.EventEmitter, ModelProperties {
// ModelProperties...
}
到此关于model
对象的源码结构就基本了解了
实现步骤
1.Model层
import * as Mongoose from 'mongoose'
// 定义需要的Document的结构
export interface IPosts extends Mongoose.Document {
title: string,
brief: string,
time: Date
content: string,
count: number,
isDelete: number
}
// 对应的Schema结构
const PostSchema: Mongoose.Schema = new Mongoose.Schema({
title: String,
brief: String,
time: { type: Date , default: Date.now },
content: String,
count: Number,
isDelete: { type: Number , default: 0 }
})
// 将model对象暴露给service
export default () => Mongoose.model<IPosts>('posts', PostSchema)
2.Service层
import postsModel from '../model/posts'
@provide('postService')
export class PostService implements IPostService{
async getPosts(): Promise<IPosts[]>{
const result: IPosts[] = await postsModel().find()
return result
}
}
上面这种方法只是我自己踩出来的写法 但是特别不优雅 如果有更好实践方法欢迎来issues
Links
Complete guide for Typescript with Mongoose for Node.js
到时候写好一个完整的demo再填github上的坑吧 留下了菜鸡的眼泪💧