在NestJs中连接MongoDB如何快速生成Schema,别再全部手写了😁😁😁

最近在开发一个后端项目,需要从另外一个后台语言转换成 NestJs 的,后端数据库使用的是 MongoDB。

背景

在使用的时候就遇到了一个问题,使用 MongoDB 会需要定义大量的 schema 配置才能做完成一个表的使用,并且类型也多,于是我想到了实现一个工具来对已有的返回数据对其进行初始化,然后生成一个初始的 schema,然后对其进行修改完善。

具体实现

假设我们有一个后台接口返回的数据是以下结构:

json 复制代码
{
  "name": "string",
  "age": {
    "type": "number",
    "required": true,
    "min": 0
  },
  "gender": {
    "type": "enum",
    "values": ["male", "female", "non-binary", "prefer not to say"]
  },
  "address": {
    "street": "string",
    "city": "string",
    "country": "string"
  },
  "friends": [
    {
      "name": "string"
    }
  ]
}

数据我们有了,接下来我们创建一个node项目来编写相关的脚本,安装相关依赖:

bash 复制代码
npm i mongoose

之后在根目录下创建一个 index.js 文件并编写一下代码:

js 复制代码
const fs = require("fs");

function generateSchemaClass(
  jsonSchema,
  className,
  generatedClasses = [],
  isSubClass = false
) {
  let tsCode = "";

  if (!isSubClass) {
    tsCode = `
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
`;
  }

  tsCode += `
@Schema()
export class ${className} {
`;

  for (const [key, value] of Object.entries(jsonSchema)) {
    if (Array.isArray(value)) {
      const typeName = capitalize(key.slice(0, -1));

      if (!generatedClasses.includes(typeName)) {
        tsCode += generateSchemaClass(
          value[0],
          typeName,
          generatedClasses,
          true
        );
        generatedClasses.push(typeName);
      }
      jsonSchema[key] = [{ type: typeName }];
    }
  }

  for (const [key, value] of Object.entries(jsonSchema)) {
    if (typeof value === "string") {
      tsCode += `
  @Prop()
  ${key}: ${value};
`;
    } else if (value.type === "enum") {
      tsCode += `
  @Prop()
  ${key}: ${value.values.join(" | ")};
`;
    } else if (value.type) {
      tsCode += `
  @Prop(${value.required ? "{ required: true }" : ""})
  ${key}: ${value.type};
`;
    } else if (Array.isArray(value)) {
      tsCode += `
  @Prop([{ type: () => ${value[0].type} }])
  ${key}: ${value[0].type}[];
`;
    }
  }

  tsCode += `}
export const ${className.toLowerCase()}Schema = SchemaFactory.createForClass(${className});
export type ${className}Document = HydratedDocument<${className}>;
`;

  return tsCode;
}

function capitalize(str) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

const jsonSchema = JSON.parse(fs.readFileSync("./index.json", "utf-8"));
const className = "Models";
const tsCode = generateSchemaClass(jsonSchema, className);
fs.writeFileSync("./path-to-output.ts", tsCode);

在上面的代码中,主要有以下步骤,如下所示

  1. 使用 Node.js 的 fs 模块用于文件的读取和写入。

  2. 创建一个主要用于生成 TypeScript 类定义的 generateSchemaClass 函数。

  3. 如果不是生成子类,则将 NestJS 和 Mongoose 的导入语句添加到生成的代码字符串中。

  4. 如果是子类,则生成一个带有 @Schema() 装饰器的类定义。

  5. 处理数组类型属性有以下步骤:

    • 对 JSON Schema 进行迭代,找出数组类型的属性。
    • 对每个数组类型的属性生成一个子类定义,并更新该属性的类型信息。
  6. 继续遍历 JSON Schema,并根据属性的类型添加相应的 @Prop 装饰器和类型定义。

  7. 将类的结束括号、SchemaFactory 创建语句和导出类型添加到代码字符串中。

  8. 实现一个 capitalize 函数用于将字符串首字母大写的辅助函数。

  9. 使用 fs 模块读取 JSON 文件,并将其内容解析为一个 JavaScript 对象。

  10. 调用 generateSchemaClass 函数,传入解析后的 JSON Schema 和目标类名,生成 TypeScript 代码。

  11. 将生成的 TypeScript 代码字符串写入到一个指定的 .ts 文件中。

通过递归生成主类和可能的子类定义,它能够处理嵌套的对象和数组类型属性。处理的结果是一个或多个装饰过的 TypeScript 类,可以在 NestJS 项目中用作 Mongoose 模型的定义。通过这种方式能够实现从数据模型到代码的自动转换,提高了开发效率并减少了手动编写模型定义时可能出现的错误。

总结

在日常开发的过程中,我们难免会遇到一些重复的工作,这个时候,我们就可以去想到实现一些工作来帮助我们去处理一下重复的工作,以提升工作效率了

最后分享两个我的两个开源项目,它们分别是:

这两个项目都会一直维护的,如果你也喜欢,欢迎 star 🚗🚗🚗

相关推荐
2601_953720824 小时前
【计算机毕业设计】基于Spring Boot的心理健康咨询与评测系统的设计与实现
java·spring boot·后端
东方小月5 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
Csvn6 小时前
🧩 ESM vs CJS 混用的 7 个「天坑」——从 TypeScript 编译到 Node 与浏览器
前端
都叫我大帅哥6 小时前
“让AI修就行”?我劝你收回这句话——来自一位Java博主的硬核反常识
后端
Csvn6 小时前
🎯 Web 性能 API 集合:Performance Observer 的 5 个冷门妙用
前端
Csvn6 小时前
深入 React 闭包陷阱:从根源上理解并根治 stale closure
前端
whyfail6 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端
用户059540174467 小时前
LangChain 记忆测试踩坑实录:这两个坑让我排查了 4 小时
前端·css
程序员黑豆7 小时前
鸿蒙应用开发:@Monitor 装饰器使用教程
前端·harmonyos