how to set one to many relation in nestjs graphql - graphql

this is my relation user entity
#OneToMany(() => DoctorSchedule, doctorSchedule => doctorSchedule.user)
#Field(type => DoctorSchedule)
#JoinColumn({ name: "doctorId" })
doctorSchedules?: DoctorSchedule[];
this is my resolver
#ResolveField((returns) => DoctorSchedule)
#UseGuards(JwtAuthGuard)
doctorSchedules(#Parent() user: User): Promise<DoctorSchedule[]> {
return this.usersService.getDoctorSchedule(user.id);
}
this is my doctor schedule entity
#ManyToOne(() => User, user => user.doctorSchedules)
#Field(type => User, { nullable: true })
user?: User;
this is my rsollver doctor schedule
#ResolveField(returns => User)
// #UseGuards(JwtAuthGuard)
user(#Parent() doctorSchedule: DoctorSchedule): Promise<User> {
return this.doctorScheduleService.getUser(doctorSchedule.doctorId);
}
many to one relation is working like:
query{
doctorSchedules{
day
}user(id:11){
first_name
last_name
}
}
output is good
but one to many is not working like:
query{
user(id:11){
email
first_name
doctorSchedules{
day
}
}
}
its giver me error "Cannot return null for non-nullable field DoctorSchedule.day."
please help me

Make sure you have the relationship in your service
Example:
method() {
return yourRepository.find({ relations: ['doctorSchedules'] });
}

Related

Eloquent querying relation based on main query

I have 4 tables:
Users with column id
Teams with column id
Roles with column id
Pivot teams_users with columns team_id user_id role_id
Goal: get teams, each team has members. Each member has a role in that team.
My approach:
Fetch teams, then fetch members and roles of that team. Loop the collection, add the role to the correct member, delete the role after.
$teams->each(function($team, $teamKey) use ($teams) {
if(empty($team->members) === false && empty($team->roles) === false) {
$team->members->each(function($member, $memberKey) use ($team) {
$team->roles->each(function($role) use ($member) {
if($member->id === $role->pivot->user_id) {
$member->role = $role;
}
});
});
}
});
My goal:
I want to do it using Eloquent and without looping the collection.
My Team model has two relations:
public function members() {
return $this->belongsToMany(User::class, "teams_users", "team_id", "user_id")->withPivot("role_id")->withTimestamps();
}
public function roles() {
return $this->belongsToMany(Role::class, "teams_users", "team_id", "role_id")->withPivot("user_id")->withTimestamps();
}
expected output should be like this:
{
teams: [
{
id: 1,
title: "Awesome team",
members: [
{
id: 1
name: "Test",
role: {
id: 1,
title: "Admin"
}
}
]
}
]
}
Your help is much appreciated.

NestJS getting relationship info to graphql

I'm trying to access a property from the many-to-many relationship model. But NestJS's GraphQL implementation won't let me. I've tried already IntersectionType, creating a custom type, ...
But everything gives me:
throw new TypeError();
^
TypeError:
at Reflect.getMetadata...
Example:
export class Model1{
#Field(() => ID)
#PrimaryKey
#Column
id: string;
#BelongsToMany(() => Model2, () => Relation )
others: (Game & { Relation : Relation })[];
}
export class Model2{
#Field(() => ID)
#PrimaryKey
#Column
id: string;
#BelongsToMany(() => Model1, () => Relation )
others: (Game & { Relation : Relation })[];
}
export class Relation {
#ForeignKey(() => Model1)
#Field({ nullable: true })
#Column
model1Id: string;
#ForeignKey(() => Model2)
#Field({ nullable: true })
#Column
model2Id: string;
#Column
some_property: string
}
How would you setup your graphql properties so I can access the some_property from the relation object?
I can access it in code. But I can't seem to setup the graphql attributes so I can query them.

Laravel lighthouse Graphql filter by method on model

I want to filter my data, base on a method on my model:
method in my model:
// . . .
public function isBatched(): bool
{
return $this->rows()->count() > 1;
}
and my qraphql:
type Invoice
{
globalId: ID! #globalId #method(name: "getKey")
localId: Int! #method(name: "getKey")
pdfUrl: String #method(name: "getPdfUrl")
number: String
poNumber: String #rename(attribute: "po_number")
deposit: Deposit #hasOne
rows: [InvoiceRow!] #hasMany
bills: [Bill!] #belongsToMany(type: "paginator", relation: "bills")
isBatched: Boolean! #method(name: "isBatched")
isCompleted: Boolean #method(name: "isPaid")
dueDate: DateTime #rename(attribute: "due_date")
total: Money #method(name: "totalAmountMoney")
}
extend type Query {
invoices: Invoice! #paginate #cache
invoicesb(isBatched: Boolean #eq): [Invoice]! #paginate
}
but it does not work, it says isBatched filed is not exist, any idea?
#eq directive works for column's databases, not for your model's method. So, one thing you can do is to use Eloquent's scopes, like
class Invoice extends Model
{
// ...
public function scopeIsBatched(Builder $query, bool $isBatched): Builder
{
// Find the way to filter by your relationship count.
// So far, I think something like:
return $query->withCount('rows')->where('rows_count', '>', 1);
}
}
Then, your schema will be like
extend type Query {
invoicesb(isBatched: Boolean #scope): [Invoice]! #paginate
}
the right way:
public function scopeIsBatched(Builder $query, bool $isBatched): Builder
{
if ($isBatched) {
return $query->withCount('rows')->having('rows_count', '>', 1);
}
return $query;
}

updateExistingPivot using the primary key instead of the foreign key

I think this question is similar to this one, however I also think my use case is slightly different.
I am successfully able to update a pivot table using updateExistingPivot when a single user exists; however instead of referencing the FK on the pivot table, I need to reference the id.
I have three tables: users, roles and role_user.
users
id|name|email
roles
id|title
role_user
id|active|user_id|role_id
For example, if I have two users in my application, the users table would look like:
id: 1|name: foo|email: fooexample#email.com
id: 2|name: bar|email: barexample#email.com
My roles table looks like this:
id: 1|title: fizz
id: 2|title: buzz
id: 3|title: bang
Each user is given 3 roles by default. So my role_user table looks like this:
id: 1|active: true|user_id: 1|role_id: 1
id: 2|active: true|user_id: 1|role_id: 2
id: 3|active: true|user_id: 1|role_id: 3
id: 4|active: true|user_id: 2|role_id: 1
id: 5|active: true|user_id: 2|role_id: 2
id: 6|active: true|user_id: 2|role_id: 3
Because updateExistingPivot looks at the FK to decide what to update, everything works great with a single user. However, when I have duplicate user_id and/or role_id FK's things start to fall apart. Instead of looking at the FK, I need to be able to look at the id in my pivot table.
I am passing my roles to a vue component from my controller like this:
// Get the roles(s) that belong to the user.
$roles = $user->roles
->sortByDesc('title')
->toJson();
I am rendering the list on screen, and when a user clicks a role, they can update it's status:
...
async handleRoleClick(event, role) {
console.log('updating role: ', role);
try {
let response = await axios.patch(`/my-path`, {
active: !this.active,
id: role.pivot.id,
});
// data getting passed is correct.
// active: false
// id: 5 <-- the id of the pivot table, not a FK value
if (response.status === 200) {
console.log('response.data', response.data);
this.active = response.data.role.pivot.active;
console.log('active: ', this.active);
} else {
console.error('Error: could not update role. ', response);
}
} catch (error) {
console.error('Error: sending patch request. ', error);
}
},
...
My update method in my controller looks like this:
$attributes = request()->validate([
'active' => 'required',
'id' => 'required',
]);
// Get the authenticated user.
$user = auth()->user();
// Update the roles' status in the pivot table.
$user->roles()->updateExistingPivot($attributes['id'], $attributes);
// Get the role that was just updated via the relationship.
$role_with_pivot = $user->roles()->where('role_user.id', $attributes['id'])->first();
return response()->json(['role' => $role_with_pivot], 200);
The data I am sending in my request headers is correct. I am not getting any errors, however my pivot table is not getting the values I am passing to it. I assume it's because I am not correctly sending the id. In my example above it would be id: 5. Because there isn't a user_id of 5 or role_id of 5, Laravel isn't sure what to do.
How can I tell Laravel to look at the id of the pivot table, and not a foreign key?
The way I am doing it though seems kind of sketchy. I'd be really interested to see if there is a more "Laravel way" of doing this. Everything else is above is the same, here is what my update method on my controller looks like.
controller
public function update(Request $request, Role $role)
{
$attributes = request()->validate([
'active' => 'required',
'id' => 'required',
]);
// Get the authenticated user.
$user = auth()->user();
// Get the requested role (row) from the pivot table.
$role = $user->roles()->where('role_user.id', $attributes['id'])->first();
// Update the requested role.
$role->pivot->active = $attributes['active'];
// Save the requested role.
$role->pivot->save();
// Get the role that was just updated via it's relationship.
$role_with_pivot = $user->roles()->where('role_user.id', $attributes['id'])->first();
return response()->json(['role' => $role_with_pivot], 200);
}
You should retrieve role id in you View instead of pivot primary key, and use role_id to update pivot table.
As stated your user has multiple roles, but only one combination of role and user id.
async handleRoleClick(event, role) {
console.log('updating role: ', role);
try {
let response = await axios.patch(`/my-path`, {
active: !this.active,
id: role.id, //change this
});
// data getting passed is correct.
// active: false
// id: 5 <-- the id of the pivot table, not a FK value
if (response.status === 200) {
console.log('response.data', response.data);
this.active = response.data.role.pivot.active;
console.log('active: ', this.active);
} else {
console.error('Error: could not update role. ', response);
}
} catch (error) {
console.error('Error: sending patch request. ', error);
}
},
it's late, but might help some artisans in the future.
You may use DB method directly or create a dedicated model/entity for that table.
e.g
DB::table('role_user')->where('id', $id);
or
RoleUser::find($id);

Update all records through model relation ship in laravel

class ModelA {
public function modelB()
{
return $this->hasMany(ModelB::class);
}
}
class ModelB {
public function modelC()
{
return $this->hasMany(ModelC::class);
}
}
class ModelC {
public function modelD()
{
return $this->hasMany(ModelD::class);
}
}
class ModelD {
//has column status_changed_date
}
I have $modelA = ModelA::find($id);
ModelA have multiple ModelB, ModelB have multiple ModelC, ModelC has multiple ModelD.
Now I want update status_changed_date for all matching records.
Is there any better way to do this. I have refered https://laravel.com/docs/5.7/eloquent-relationships#updating-many-to-many-relationships
but couldn't find out a solution.
Please help to solve this.
$modelAs = ModelA::with('modelB.modelC.modelD')->find($id)
before you can use that way :
$modelA->modelB->each->modelC->each->modelC->each->update([
'field' => 'value'
]);
or reduce values to ids, this only made one query :
$ids = [];
$modelA->modelB->each->modelC->each->modelC->each(function ($c) use($ids) {
$ids[] = $c->id;
});
ModelC::whereIn('id', $ids)->update([
'field' => 'value'
});
if each->modelC->each is not working, use method notation
Instead of making all this update, make one common table of common fields and directly update that table.
For more
Laravel Polyformic relationships

Resources