0

I'm setting up many to many relations in my loopback 4 application. Currently I am using this answer as a guide but after the repository and controller creation I don't know how to continue.

Currently I have three tables for the relation: Course, Language, and LanguageCourse. This means a Course can have many languages and a Language can belong to many courses.

My language-course.model.ts looks like this:

import {Course} from './course.model';
import {Language} from './language.model';

@model({settings: {}})
export class LanguageCourse extends Entity {
  @property({
    type: 'number',
    id: true,
  })
  id?: number;

  @belongsTo(() => Course)
  courseId?: number;

  @belongsTo(() => Language)
  languageId?: number;

  constructor(data?: Partial<LanguageCourse>) {
    super(data);
  }
}

export interface LanguageCourseRelations {
  // describe navigational properties here
}

export type LanguageCourseWithRelations = LanguageCourse &
  LanguageCourseRelations;

My course.model.ts looks like this (I have already set up a one to many relation in this model):

import {User, UserWithRelations} from './user.model';

@model({settings: {}})
export class Course extends Entity {
  @property({
    type: 'number',
    id: true,
  })
  id?: number;

  @property({
    type: 'string',
  })
  name?: string;

  @property({
    type: 'string',
  })
  description?: string;

  @belongsTo(() => User)
  userId?: number;

  @property({
    type: 'string',
    default: 'active',
  })
  state?: string;

  @property({
    type: 'string',
    default: 'rookie',
  })
  level?: string;

  @property({
    type: 'string',
  })
  course_photo?: string;

  constructor(data?: Partial<Course>) {
    super(data);
  }
}

export interface CourseRelations {
  user?: UserWithRelations;
}

export type CourseWithRelations = Course & CourseRelations;

And my language.model.ts looks like this:


@model({settings: {}})
export class Language extends Entity {
  @property({
    type: 'number',
    id: true,
  })
  id?: number;

  @property({
    type: 'string',
  })
  name?: string;

  constructor(data?: Partial<Language>) {
    super(data);
  }
}

export interface LanguageRelations {
  // describe navigational properties here
}

export type LanguageWithRelations = Language & LanguageRelations;

I would like to do a GET request to, for example /courses/{id} endpoint (and /courses as well) and have in the response all the languages that course has but I don't know how to make it work. Also I would like this to work in /languages endpoint.

Thanks for your time!

1 Answers1

0

Unfortunately, there is no proper default many to many relations defined in loopback 4 documentation.

But it seems like you have already tried implementing to create a bridging connecting model language-course.model.ts which is good. Now you have to create the repository and controller for this model. Once that done you can write your own custom logic which will handle storing and retrieving of the data.

For example, As you said you wish to query and fetch all list of all the languages based on a courses ID, your CourseLanguage model should look something like

import {Course} from './course.model';
import {Language} from './language.model';

@model({settings: {}})
export class LanguageCourse extends Entity {
  @property({
    type: 'number',
    id: true,
  })
  id?: number;

  @property({
    type: 'string',
  })
  courses: string;

  @property({
    type: 'array',
    itemType: 'string',
    required:true
  })
  languages: string[];

  constructor(data?: Partial<LanguageCourse>) {
    super(data);
  }
}

export interface LanguageCourseRelations {
  // describe navigational properties here
}

export type LanguageCourseWithRelations = LanguageCourse &
  LanguageCourseRelations;

What we are doing above is we are creating two new properties courses which will be the ID of the course and languages which will be an array holding all the languages for that course. Once this is done.

Next, you will have to work on the controller for this model Follow these following steps for GET all languages based on course ID API

Create a custom controller with route /course/{id} as mentioned by you.

Inside that controller, write your custom code as follows:

@get('/course/{id}', {
    responses: {
      '204': {
        description: 'Fetching the list of all the languages as per course ID',
      },
    },
  })
  async fetchListOfLanguagesAsPerCourseId(@param.path.string('id') id: string) {
  /** 
  * Search for the course in `CourseLanguage` collection or table by using the course id 
  **/
  let searchedCourseLanguageObject = await this.courseLanguageRepository.findOne({where: {courses: id}});

  /** 
  * If the course does not exists, throw an error 
  **/
  if(searchedCourseLanguageObject === null || undefined) {
    throw new HttpErrors.NotFound("Course does not have any languages")
  }

  /** 
  * If the course exists, it will have array languages with all the IDs of the languages from LAnguages collection or table in the database related to the course
  **/
let arrayOfLanguagesId = searchedCourseLanguageObject.languages;

/** 
  * Now go to the language table and fetch all the languages object whose IDs are present in the above array
  **/
  let listOfLanguages = await this.languagesRepository.find({where: {id: { inq: arrayOfLanguagesId }}});

/** 
  * Above code will look for all the languages ID in the languages table and return back objects of the language whose ID exist in the array arrayOfLanguagesId
  **/
return listOfLanguages

  }

Hopefully, this is not too intimidating, when you will implement it, it is easy. Write to me if you will still face any problem. Thanks Hopefully this helps.

Yash Rahurikar
  • 186
  • 1
  • 10