7

I am in the process of implementing mongoose models with typescript as outlined in this article: https://github.com/Appsilon/styleguide/wiki/mongoose-typescript-models and am not sure of how this translates when you are working with arrays of subdocuments. Let's say I have the following model and schema definitions:

interface IPet {  
    name: {type: mongoose.Types.String, required: true},   
    type: {type: mongoose.Types.String, required: true}   
}

export = IPet


interface IUser {   
    email: string;    
    password: string;   
    displayName: string;   
    pets: mongoose.Types.DocumentArray<IPetModel>   
};

export = IUser;


import mongoose = require("mongoose");  
import IUser = require("../../shared/Users/IUser");   
interface IUserModel extends IUser, mongoose.Document { }

import mongoose = require("mongoose");   
import IPet = require("../../shared/Pets/IPet");   
interface IPetModel extends IPet, Subdocument { }

code that would add a new pet to the user.pet subdocument:

addNewPet = (userId: string, newPet: IPet){
    var _user = mongoose.model<IUserModel>("User", userSchema);
    let userModel: IUserModel = await this._user.findById(userId);
    let pet: IPetModel = userModel.pets.create(newPet);
    let savedUser: IUser = await pet.save();
}

After reviewing the link, this seems to be the ideal approach necessary for handling subdocuments. However, this scenario seems to result in a CasterConstructor exception being thrown:

TypeError: Cannot read property 'casterConstructor' of undefined at Array.create.

Is it the right approach to dealing with Subdocuments when using mongoose models as outlined in the linked article above?

Zlatko
  • 18,936
  • 14
  • 70
  • 123
user1790300
  • 2,143
  • 10
  • 54
  • 123
  • I have not created mongoose model with typescript before. I guess let pet: IPetModel = userModel.pets.create(newPet); is incorrect. Can you try this solution? addNewPet = (userId: string, newPet: IPet){ var _user = mongoose.model("User", userSchema); let userModel: IUserModel = await this._user.findById(userId); userModel.pets.push(newPet); await userModel.save(); } Hope it helps – dnp1204 Mar 15 '18 at 19:35
  • Can you try using classes instead of interfaces up there? It's just a hunch, but I know i.e. in Angular apps that Typescript metadata (types etc) do not make it to compiled code, _and that includes interfaces!_ Meaning, mongoose is asking for Constructor of that nested model/schema, but it cannot find it because interface dissapeared in compilation. – Zlatko Mar 22 '18 at 09:38

1 Answers1

0

you can try this package https://www.npmjs.com/package/mongoose-ts-ua

@setSchema()
class User1 extends User {
    @prop()
    name?: string;

    @setMethod
    method1() {
        console.log('method1, user1');
    }
}

@setSchema()
class User2 extends User {
    @prop({ required: true })
    name?: string;

    @prop()
    child: User1;
}

export const User2Model = getModelForClass<User2, typeof User2>(User2);

usage

let u2 = new User2Model({ child: { name: 'u1' } });