ts-mongoose
ts-mongoose copied to clipboard
self-references
Hi How would I model a self-reference, such as
const UserSchema = new mongoose.Schema({
name: { type: String },
superior: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
});
Both Type.schema().of(UserSchema)
and Type.ref(Type.objectId()).of("User", UserSchema)
will complain:
Block-scoped variable 'UserSchema' used before its declaration.
Could you provide a use case for such refernece?
The classic one is a person / employee that has a supervisor which is also a person / employee. In my case I need to reference to a "parent" or predecessor object
I've found a workaround:
In mongoose, you have an add
method on models that allows you to concatenate model definitions (https://mongoosejs.com/docs/api/schema.html#schema_Schema-add).
I split my model declaration in two steps. First I add everything not related to current model and next with add
I add self references.
const UserSchema = createSchema({
name: Type.string({ required: true }),
office: Type.string()
});
UserSchema.add(
createSchema({
superior: Type.schema().of(UserSchema),
accountant: Type.schema().of(UserSchema)
})
);
It works for me as UserSchema
is declared before using it in self references.
Hope it helps
I've found a workaround:
In mongoose, you have an
add
method on models that allows you to concatenate model definitions (https://mongoosejs.com/docs/api/schema.html#schema_Schema-add).I split my model declaration in two steps. First I add everything not related to current model and next with
add
I add self references.const UserSchema = createSchema({ name: Type.string({ required: true }), office: Type.string() }); UserSchema.add( createSchema({ superior: Type.schema().of(UserSchema), accountant: Type.schema().of(UserSchema) }) );
It works for me as
UserSchema
is declared before using it in self references.Hope it helps
This above example works for me if I only define like this and do not use it. Once I need to assign/access self-reference property, such as user.superior =
and it will throw an exception.
@grimmer0125 What kind of exception? It's fine on my side
code snippet:
- definition:
const phaseTaskSchema = createSchema(
{
status: Type.number(),
}
);
phaseTaskSchema.add(
createSchema({
seriesRef: Type.ref(Type.objectId()).to("PhaseTask", phaseTaskSchema)
})
);
const model = typedModel("PhaseTask", phaseTaskSchema);
- run:
const p = new db.PhaseTask();
p.seriesRef = p._id;
await p.save();
TypeScript: 3.7.2
run tsc
:
yarn run v1.16.0 $ tsc index.ts:120:5 - error TS2339: Property 'seriesRef' does not exist on type 'Document & { status: number; _id: ObjectId; __v: number; } & {}'.
120 p.seriesRef = p._id; ~~~~~~~~~
Found 1 error.
error Command failed with exit code 2.
@grimmer0125 Add seriesRef: Type.ref(Type.objectId())
in your createSchema
object
Thanks. @tuarrep
The modified code:
const phaseTaskSchema = createSchema(
{
status: Type.number(),
seriesRef: Type.ref(Type.objectId())
}
);
phaseTaskSchema.add(
createSchema({
seriesRef: Type.ref(Type.objectId()).to("PhaseTask", phaseTaskSchema)
})
);
This time tsc
compliling succeeds. But when I run the testing code, got
throw new TypeError(`Invalid schema configuration: \`${name}\` is not ` +
^
TypeError: Invalid schema configuration: `To` is not a valid type at path `seriesRef.to`. See http://bit.ly/mongoose-schematypes for a list of valid schema types.
at Schema.interpretAsType (/Users/grimmer/git/v2/server/node_modules/mongoose/lib/schema.js:796:11)
at Schema.path (/Users/grimmer/git/v2/server/node_modules/mongoose/lib/schema.js:572:27)
at Schema.add (/Users/grimmer/git/v2/server/node_modules/mongoose/lib/schema.js:437:12)
at Schema.add (/Users/grimmer/git/v2/server/node_modules/mongoose/lib/schema.js:426:14)
at new Schema (/Users/grimmer/git/v2/server/node_modules/mongoose/lib/schema.js:117:10)
at Object.exports.createSchema (/Users/grimmer/git/v2/server/node_modules/ts-mongoose/createSchema.js:5:12)
at Object.<anonymous> (/Users/grimmer/git/v2/server/service/mongoose/PhaseTask.ts:9:23)
PhaseTask.ts:9:23 is this line let phaseTaskSchema = createSchema(
For reference, here a working snippet from my code base:
export const ProductSchema = createSchema({
diluent: Type.object({ required: true }).of({
paintbrush: Type.ref(Type.objectId()),
spray: Type.ref(Type.objectId())
})
});
/* WORKAROUND: https://github.com/BetterCallSky/ts-mongoose/issues/35 */
ProductSchema.add(
createSchema({
diluent: Type.object({ required: true }).of({
paintbrush: Type.ref(Type.objectId()).to("Product", ProductSchema),
spray: Type.ref(Type.objectId()).to("Product", ProductSchema)
})
})
);
I've found a workaround:
In mongoose, you have an
add
method on models that allows you to concatenate model definitions (https://mongoosejs.com/docs/api/schema.html#schema_Schema-add).I split my model declaration in two steps. First I add everything not related to current model and next with
add
I add self references.const UserSchema = createSchema({ name: Type.string({ required: true }), office: Type.string() }); UserSchema.add( createSchema({ superior: Type.schema().of(UserSchema), accountant: Type.schema().of(UserSchema) }) );
It works for me as
UserSchema
is declared before using it in self references.Hope it helps
I think it would be nice to have this kind of example in the docs - for me that'd be enough to close the issue.