skip to Main Content

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

2

Answers


  1. I think you have to use in your populate statement card as single as by default mongo uses a single name for the model and a plural name for the table

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search