I'm trying to seed data for my db but both my schema reference each other so I'm not sure how it's possible to seed one before the other.
I want to use fakerjs to have some data to play with, but I'm a bit confused how I'd approach it.
Here are my Schemas, they're super simple and both ref each other:
import mongoose from "mongoose";
import { loadType } from "mongoose-currency";
const Schema = mongoose.Schema;
loadType(mongoose);
const CategorySchema = new Schema(
{
name: String,
expenses: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Expense",
},
],
},
{ timestamps: true, toJSON: { getters: true } }
);
const Category = mongoose.model("Category", CategorySchema);
export default Category;
And the other:
import mongoose from "mongoose";
import { loadType } from "mongoose-currency";
const Schema = mongoose.Schema;
loadType(mongoose);
const ExpenseSchema = new Schema(
{
name: String,
price: {
type: mongoose.Types.Currency,
currency: "USD",
get: (v) => v / 100,
},
date: {
type: Date,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
},
{ timestamps: true, toJSON: { getters: true } }
);
const Expense = mongoose.model("Expense", ExpenseSchema);
export default Expense;
Does anyone know how I'd go about seeding them if they both rely on each other?
Refs to children documentation explains this situation.
E.g. ("mongoose": "^7.3.1")
// @ts-nocheck
import mongoose from 'mongoose';
import util from 'util';
import { config } from '../../config';
const CategorySchema = new mongoose.Schema({
name: String,
expenses: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Expense',
},
],
});
const Category = mongoose.model('Category', CategorySchema);
const ExpenseSchema = new mongoose.Schema({
name: String,
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category',
},
});
const Expense = mongoose.model('Expense', ExpenseSchema);
(async function main() {
mongoose.set('debug', true);
try {
await mongoose.connect(config.MONGODB_URI);
await Promise.all([Category, Expense].map((m) => m.collection.drop()));
// seed
const [c1, c2] = [{ name: 'c1' }, { name: 'c2' }].map((v) => new Category(v));
const [e1, e2, e3] = [
{ name: 'e1', category: c1._id },
{ name: 'e2', category: c1._id },
{ name: 'e3', category: c2._id },
].map((v) => new Expense(v));
c1.expenses.push(e1, e2);
c2.expenses.push(e3);
await Promise.all([c1, c2].map((v) => v.save()));
await Promise.all([e1, e2, e3].map((v) => v.save()));
// populate
const c = await Category.findOne({ name: 'c1' }).populate('expenses').exec();
console.log(c?.toObject());
const e = await Expense.findOne({ name: 'e1' })
.populate({ path: 'category', populate: { path: 'expenses' } })
.exec();
console.log(util.inspect(e?.toObject(), false, null));
} catch (error) {
console.error(error);
} finally {
await mongoose.connection.close();
}
})();
Debug logs:
Mongoose: categories.drop()
Mongoose: expenses.drop()
Mongoose: categories.insertOne({ name: 'c1', expenses: [ ObjectId("649d8f7d038538fabd2e1ce3"), ObjectId("649d8f7d038538fabd2e1ce4") ], _id: ObjectId("649d8f7d038538fabd2e1ce1"), __v: 0}, {})
Mongoose: categories.insertOne({ name: 'c2', expenses: [ ObjectId("649d8f7d038538fabd2e1ce5") ], _id: ObjectId("649d8f7d038538fabd2e1ce2"), __v: 0}, {})
Mongoose: expenses.insertOne({ name: 'e1', category: ObjectId("649d8f7d038538fabd2e1ce1"), _id: ObjectId("649d8f7d038538fabd2e1ce3"), __v: 0}, {})
Mongoose: expenses.insertOne({ name: 'e2', category: ObjectId("649d8f7d038538fabd2e1ce1"), _id: ObjectId("649d8f7d038538fabd2e1ce4"), __v: 0}, {})
Mongoose: expenses.insertOne({ name: 'e3', category: ObjectId("649d8f7d038538fabd2e1ce2"), _id: ObjectId("649d8f7d038538fabd2e1ce5"), __v: 0}, {})
Mongoose: categories.findOne({ name: 'c1' }, {})
Mongoose: expenses.find({ _id: { '$in': [ ObjectId("649d8f7d038538fabd2e1ce3"), ObjectId("649d8f7d038538fabd2e1ce4") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined })
{
_id: new ObjectId("649d8f7d038538fabd2e1ce1"),
name: 'c1',
expenses: [
{
_id: new ObjectId("649d8f7d038538fabd2e1ce3"),
name: 'e1',
category: new ObjectId("649d8f7d038538fabd2e1ce1"),
__v: 0
},
{
_id: new ObjectId("649d8f7d038538fabd2e1ce4"),
name: 'e2',
category: new ObjectId("649d8f7d038538fabd2e1ce1"),
__v: 0
}
],
__v: 0
}
Mongoose: expenses.findOne({ name: 'e1' }, {})
Mongoose: categories.find({ _id: { '$in': [ ObjectId("649d8f7d038538fabd2e1ce1") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined })
Mongoose: expenses.find({ _id: { '$in': [ ObjectId("649d8f7d038538fabd2e1ce3"), ObjectId("649d8f7d038538fabd2e1ce4") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined })
{
_id: new ObjectId("649d8f7d038538fabd2e1ce3"),
name: 'e1',
category: {
_id: new ObjectId("649d8f7d038538fabd2e1ce1"),
name: 'c1',
expenses: [
{
_id: new ObjectId("649d8f7d038538fabd2e1ce3"),
name: 'e1',
category: new ObjectId("649d8f7d038538fabd2e1ce1"),
__v: 0
},
{
_id: new ObjectId("649d8f7d038538fabd2e1ce4"),
name: 'e2',
category: new ObjectId("649d8f7d038538fabd2e1ce1"),
__v: 0
}
],
__v: 0
},
__v: 0
}