You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mongoose双向引用Schema时用Faker.js填充初始数据?

解决Mongoose双向关联Schema的初始数据填充问题(基于Faker.js)

处理这种双向引用的Schema,核心思路是分三步异步执行:先创建其中一方的基础数据,再创建关联的另一方并绑定已生成的ID,最后反向更新初始数据的关联数组。具体实现如下:

步骤说明

  1. 先创建分类数据:因为支出(Expense)必须关联一个分类ID,而分类(Category)的expenses数组可以后续补充,优先生成分类更合理。
  2. 生成支出数据并关联分类:每个支出随机绑定一个已创建的分类ID。
  3. 反向更新分类的关联数组:将每个分类对应的支出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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:37:26