node.jstypescriptmongodbmongoosemongoose-populate

Mongoose is returning that the schema does not exist when it really does


I am trying to create a multitenant DB with node js and MongoDB, and it works fine, I can create a new database with a tag, for example: main database store, tenant: store_fool, and each tenant has their tables (collections).

So, what's the problem?

I had this model:

const BoardSchema = new Schema<Board, Model<Board>>({
    name: {
        type: String,
        required: true
    },
    cards: [{
        type: SchemaTypes.ObjectId,
        ref: 'cards'
    }],
    color: {
        type: String,
        default: '#55AC79'
    }
})

const BoardModel = async (id: string) => {
    try {
        const db = await getTenantDb(id);
        return db!.model('boards', BoardSchema);
    } catch (error) {
        console.log(error);
        throw error;
    }
}

And this is my card model:

const CardSchema = new Schema<Card, Model<Card>>({
    name: {
        type: String,
        required: true
    },
    description: {
        type: String,
        required: true
    }
})

const CardModel = async (id: string) => {
    try {
        const db = await getTenantDb(id);
        return db!.model('cards', CardSchema)
    } catch (error) {
        console.log(error);
        throw error;
    }
}

I tried to get the info on boards with these lines:

const Board = await BoardModel(x_tenant as string);
const data = await Board.find();

And it works fine, if I show the collection on my MongoDB Compass GUI, it sends me the correct collections.

The problem is when I tried to populate cards

const Board = await BoardModel(x_tenant as string);
const data = await Board.find().populate('cards'); //it causes error

I got the following error:

MissingSchemaError: Schema hasn't been registered for model "cards".

But in MongoDB Compass GUI the collection exists, if I don't populate the prop, it works.

enter image description here

Note The id of cards in boards collection exists on cards collection


Solution

  • I'm not familiar with some of your syntax for creating your models but the MissingSchemaError: Schema hasn't been registered for model "cards". is thrown by mongoose when it can't find the particular model to use when doing the populate on the field you specified. However, implementing these changes should resolve your issues.

    The correct format for referencing your cards array would be:

    cards: [{
       type: SchemaTypes.ObjectId,
       ref: 'Card' //< Change to this
    }],
    

    When you create the Models use the single, title-cased version of your collection names. So this:

    return db!.model('Board', BoardSchema); //< Change to this
    
    return db!.model('Card', CardSchema) //< Change to this
    

    With these changes in place it is often the case, depending on your project, that you need to explicitly pass the model name like this:

    const data = await Board.find().populate({path: 'cards', model: Card});
    

    See mongoose populate and Populate with TypeScript for further reading.