问题
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