Loopback 4 include nested relations

不问归期 提交于 2021-02-08 06:32:13

问题


Recently loopback team added support to the inclusion of nested relation. Reference https://loopback.io/doc/en/lb4/HasMany-relation.html#query-multiple-relations. But it doesn't cover the rest api url to get nested relations. This is what I have tried.

http://[::1]:3000/users?filter[include][0][relation]=carts&filter[include][0][scope]filter[include][0][relation]=product

I have three models users, carts, products. Users have has-many carts and carts belongs-to product. My loopback/cli version is 1.27.0

user.repository.ts

constructor(
    @inject('datasources.farm') dataSource: FarmDataSource,  @repository.getter('CartRepository') protected cartRepositoryGetter: Getter<CartRepository>,
  ) {
    super(Users, dataSource);
    this.carts = this.createHasManyRepositoryFactoryFor('carts', cartRepositoryGetter,);
    this.registerInclusionResolver('carts', this.carts.inclusionResolver);

  }

cart.repository.ts

 constructor(
    @inject('datasources.farm') dataSource: FarmDataSource, @repository.getter('UsersRepository') protected usersRepositoryGetter: Getter<UsersRepository>, @repository.getter('ProductRepository') protected productRepositoryGetter: Getter<ProductRepository>,
  ) {
    super(Cart, dataSource);
    this.product = this.createBelongsToAccessorFor('product_id', productRepositoryGetter);
    this.registerInclusionResolver('product', this.product.inclusionResolver);

    this.users = this.createBelongsToAccessorFor('user_id', usersRepositoryGetter);
    this.registerInclusionResolver('users', this.users.inclusionResolver);
  }
}

product.repository.ts

constructor(
    @inject('datasources.farm') dataSource: FarmDataSource, @repository.getter('PurchaseRepository') protected purchaseRepositoryGetter: Getter<PurchaseRepository>, @repository.getter('StockRepository') protected stockRepositoryGetter: Getter<StockRepository>, ) {
    super(Product, dataSource);


    this.registerInclusionResolver('stocks', this.stocks.inclusionResolver);
    this.registerInclusionResolver('purchases', this.purchases.inclusionResolver);

  }

Thanks in advance


回答1:


I have successfully implemented relations with MySQL as the datasource. The documentation does share that using a non-relational databases will have unexpected behavior. If that's your case, then you should check out their progress.. loopback relations open issue

Our example models will be Question (Source) and Response (Target). Question has a hasMany relation with Response

Configure your models to handle the relation, one relation at a time

  • You should add a new property to your Question model with the @hasMany decorator which will look something like this

    @hasMany(() => Response, {keyTo: 'question_id', name: 'responses'}) responses?: Response[]

  • Notice that keyTo is the foreign key that will allow the relation to work and name is just the name of the relation

  • In your Question model add the foreign key property if you haven't defined it already. It can be done with the regular @property() decorator OR like the following

    @belongsTo(() => Question, {name: 'question', keyTo: 'question_id'}) question_id?: number;

Within your source model repository (Question) you need to provide access to target model (Response) similar to the following:

export class QuestionRepository extends DefaultCrudRepository<
  Question,
  typeof Question.prototype.question_id,
  QuestionRelations
  > {
  public readonly responses: HasManyRepositoryFactory<
    Response,
    typeof Question.prototype.question_id
  >;
  constructor (
    @inject('datasources.myDB') dataSource: MyDBDataSource,
    @repository.getter('ResponseRepository') responseRepository: Getter<ResponseRepository>,
  ) {
    super(Question, dataSource);
    this.responses = this.createHasManyRepositoryFactoryFor(
      'responses',
      responseRepository
    );
    this.registerInclusionResolver('responses', this.responses.inclusionResolver);
  }
}
  • Make sure you add the last line that registers the inclusion resolver

Now your relation should be set up! To use it you would just want to create a remote method within a controller. The loopback team does communicate that a new separate controller should be created for relational cases. So in this case you would create a controller called question-response.controller.ts

Now you will just need to pass a filter object to the method you are interested in. Lets just use the .find() method since its the easiest. It should look like the following:

@get('/question/{questionId}/response_data')
  async findQuestionWithResponses(
    @param.path.number('questionId') questionId: typeof Question.prototype.question_id,
      @param.query.object('filter', getFilterSchemaFor(Question)) filter?: Filter<Question>
  ): Promise<any> {
    if (!filter) filter = {};
    filter.include = [{ relation: 'responses' }];
    return this.questionRepository.findById(questionId, filter);
  }

Hopes this helps!

Also for the nest relation it would look like the example in the documentation like the following, just make sure all your relations are set up :)

customerRepo.find({
  include: [
    {
      relation: 'orders',
      scope: {
        where: {name: 'ToysRUs'},
        include: [{relation: 'manufacturers'}],
      },
    },
  ],
});


来源:https://stackoverflow.com/questions/59435371/loopback-4-include-nested-relations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!