Taking the context of your question, a many-to-many relationship can be implemented in lb4 as below.
The jobs model (a sample) -
@model({
name: 'jobs',
})
export class Job extends Entity {
@property({
type: 'number',
id: true,
})
id: number;
@property({
type: 'string',
required: true,
})
name: string;
// Other columns of the table.....
constructor(data?: Partial<Job>) {
super(data);
}
}
The categories model (a sample) -
@model({
name: 'categories',
})
export class Category extends Entity {
@property({
type: 'number',
id: true,
})
id: number;
@property({
type: 'string',
required: true,
})
name: string;
// Other columns of the table.....
constructor(data?: Partial<Category>) {
super(data);
}
}
In the Job categories relationship model, we are going to implement the belongs to relationship with both Job and Category Models. This will ensure m:n relationship.
@model({
name: 'job_categories',
})
export class JobCategory extends Entity {
@property({
type: 'number',
id: true,
})
id: number;
@belongsTo(() => Job)
job_id: number;
@belongsTo(() => Category)
category_id: number;
constructor(data?: Partial<JobCategory>) {
super(data);
}
}
Now, using lb4 CLI, you can create a repository and REST controller for job categories model and use the find methods there to fetch data.
Unfortunately, includes parameter in Filter class for find methods is not yet implemented in lb4. Its still WIP. Refer this thread from loopback-next repo for updates. Until then, you may have to add custom logic t controller or repository classes to achieve this.
Two suggested approaches from my side are below.
- Configure belongs to relation in repository (Refer documentation here) and use it inside controller to fetch are respond with related data (Refer implementation here). You may need to create your own response model for this. We created our own DTO for this purpose. You can also return 'any' type as response for this but that's not recommended.
- You can execute your own join query if needed. That's native query approach. But, unfortunately again execute function in repository class is not implemented yet. See here. Its available in dts though. So, we implemented a work around until its implemented. We created a Base repository class which will be inherited by all repository classes in our application (replacing all extends DefaultCrudRepository with extends AppDefaultCrudRepository). Here is the implementation for base repository.
export abstract class AppDefaultCrudRepository<
T extends Entity,
ID
> extends DefaultCrudRepository<T, ID> {
constructor(
entityClass: typeof Entity & {
prototype: T;
},
dataSource: AppDataSource,
) {
super(entityClass, dataSource);
}
execute(
command: Command,
parameters: NamedParameters | PositionalParameters,
options?: Options,
): Promise<AnyObject> {
// Commented below statement until it is implemented in lb4
// return super.execute(command, parameters, options);
return this.dataSource.execute(command, parameters, options);
}
}
Hope this helps with your question #1. For question #2, you already mentioned the approach. That works.