The code of this project is available at https://github.com/veglos/nodejs-typeorm-mongodb-inheritance
The problem
A few days ago I started working with Node.js, TypeORM and MongoDB, and naturally I wanted to reflect my domain’s model into collections. Everything went smoothly until I hit some classes that inherited from an abstract class.
The solution is not complex, but I couldn’t find any explicit example on the web (and hence this article).
The Solution
diagram of class inheritance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
export abstract class Media {
@ObjectIdColumn()
_id: string;
@Column()
_type: string;
@Column()
title: string;
}
@Entity("media")
export class Video extends Media {
@Column()
director: string;
@Column()
length: number;
}
@Entity("media")
export class Book extends Media {
@Column()
author: string;
@Column()
pages: number;
}
Notice how the abstract class doesn’t have an @Entity decorator. Also, Video and Book classes both have the @Entity decorator pointing to the “media” collection (Note: They can point to different collections if desired).
We need the _type property in order to know what class should be instanced when fetching from the database.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async function InitializeDB(): Promise<DataSource> {
const dataSource = new DataSource({
useUnifiedTopology: true,
type: "mongodb",
host: process.env.MONGODB_HOST,
port: Number(process.env.MONGODB_PORT),
username: process.env.MONGODB_USERNAME,
password: process.env.MONGODB_PASSWORD,
database: process.env.MONGODB_DATABASE,
entities: [Video, Book],
});
return await dataSource.initialize();
}
async function Insert(dataSource: DataSource, media: Media) {
if (media instanceof Video)
return await dataSource.getMongoRepository(Video).insertOne(media);
if (media instanceof Book)
return await dataSource.getMongoRepository(Book).insertOne(media);
}
Finally the insertion is trivial. We only need to register the Video and Book classes to the DataSource, not the abstract class.