如何在Mongoose双向引用Schema时用Faker.js填充初始数据?
解决Mongoose双向关联Schema的初始数据填充问题(基于Faker.js)
处理这种双向引用的Schema,核心思路是分三步异步执行:先创建其中一方的基础数据,再创建关联的另一方并绑定已生成的ID,最后反向更新初始数据的关联数组。具体实现如下:
步骤说明
- 先创建分类数据:因为支出(
Expense)必须关联一个分类ID,而分类(Category)的expenses数组可以后续补充,优先生成分类更合理。 - 生成支出数据并关联分类:每个支出随机绑定一个已创建的分类ID。
- 反向更新分类的关联数组:将每个分类对应的支出ID批量添加到该分类的
expenses字段中。
完整代码示例(seed.js)
首先确保安装依赖:
npm install mongoose @faker-js/faker
然后编写填充脚本:
import mongoose from "mongoose"; import { faker } from "@faker-js/faker"; import Category from "./path/to/Category.js"; // 替换为你的Category模型路径 import Expense from "./path/to/Expense.js"; // 替换为你的Expense模型路径 // 连接数据库 await mongoose.connect("mongodb://localhost:27017/your-db-name"); // 替换为你的数据库连接字符串 async function seedData() { try { // 先清空现有数据(可选,测试环境用) await Category.deleteMany({}); await Expense.deleteMany({}); // 1. 创建分类数据 const categories = []; const categoryCount = 5; // 生成5个分类 for (let i = 0; i < categoryCount; i++) { const category = new Category({ name: faker.commerce.department(), // 用Faker生成分类名 }); await category.save(); categories.push(category); } // 2. 创建支出数据并关联分类 const expenses = []; const expenseCount = 20; // 生成20条支出 for (let i = 0; i < expenseCount; i++) { const randomCategory = faker.helpers.arrayElement(categories); const expense = new Expense({ name: faker.commerce.productName(), // 支出名称 price: faker.commerce.price({ min: 1, max: 1000, dec: 0 }) * 100, // 注意mongoose-currency存的是分,所以乘100 date: faker.date.past(), // 随机过去日期 category: randomCategory._id, // 关联分类ID }); await expense.save(); expenses.push(expense); } // 3. 反向更新分类的expenses数组 for (const category of categories) { // 筛选出当前分类下的所有支出ID const categoryExpenses = expenses.filter(exp => exp.category.toString() === category._id.toString()); const expenseIds = categoryExpenses.map(exp => exp._id); // 更新分类的expenses字段 await Category.findByIdAndUpdate(category._id, { expenses: expenseIds }); } console.log("数据填充完成!"); } catch (error) { console.error("填充数据出错:", error); } finally { // 关闭数据库连接 await mongoose.disconnect(); } } // 执行填充函数 seedData();
关键点说明
- mongoose-currency的价格处理:因为该类型存储的是货币的最小单位(比如美元的分),所以生成价格时要乘以100,避免精度问题。
- 异步操作顺序:所有数据库操作必须用
await确保顺序执行,否则会出现ID未生成就引用的错误。 - 批量更新优化:如果数据量很大,可以用
bulkWrite来优化第三步的更新操作,提升效率。
内容的提问来源于stack exchange,提问作者Mathew
相关产品推荐
相关产品推荐

