I have a client query that should return notifications objects but the returned data is a reference to a many to many record:
returnNotifications: async (root, args, {res, req}) => {
const notifications = await prisma.user.findMany({
where: {id: 1},
select: {
notifications: true,
},
});
console.log(...notifications);
return notifications;
},
returns:
{ notifications: [ { userId: 1, notificationId: 7, watched: false } ] }
My Prisma schema:
model Notification {
id Int @id @default(autoincrement())
actor_id Int
link String?
movie_id Int?
message String
icon String?
thumbnail String?
users NotificationsOnUsers[]
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
user_name String @unique
password String
movies Movie[]
notifications NotificationsOnUsers[]
followedBy User[] @relation("UserFollows", references: [id])
following User[] @relation("UserFollows", references: [id])
}
model NotificationsOnUsers {
user User @relation(fields: [userId], references: [id])
userId Int
notification Notification @relation(fields: [notificationId], references: [id])
notificationId Int
watched Boolean
@@id([userId, notificationId])
}
I would expect this to return all notifications connected to the user (1).
I think prisma calls that include
, meaning “include” this object, whereas select
means “select this field”, which is just the id
in this case.
Instead of querying the user table I’ve changed the query to target the relation table between notifications and users:
returnNotifications: async (root, args, {res, req}) => {
const userNotifications = await prisma.notificationsOnUsers.findMany({
where: {userId: 1},
include: {notification: true},
});
console.log(userNotifications);
return userNotifications
},
Which returns an array:
[
{
userId: 1,
notificationId: 7,
watched: false,
notification: {
id: 7,
actor_id: 1,
link: null,
movie_id: 438631,
message: 'alucardu has added Dune to their watchlist.',
icon: null,
thumbnail: null
}
}
]
The return value is the desired result, so I’m happy in that regard. The idea is that there’s a single notification which is shared between a lot of users, so the watched property (shows the notification in grey if it has been seen) cannot go into the notification object itself, since it will be different for each user. So I put it on the field of the relationship object. Is this approach okay? Thanks for pointing out include
Perhaps; I can’t say what your model is but in most systems I would argue that a notification is a one-to-many. One user, many notifications.
A “notification” that alerts many users sounds more like an event which should generate notifications.
For example, let’s take youtube. You have a video, and you have mutations on it, such as “release”. When a video is released, that mutation creates a “release” event, which then generates a notification for each user that has subscribed to notifications (via the notification bell).
Thus, one event, many notifications, each with its own discrete status, which then allows you to delete the notifications on a per-user basis (as one user shouldn’t be able to delete a notification for all other users).
type User {
notifications: [Notification]
}
type Notification {
user: User
event: Event
message: String
}
type Event {
type: EVENT_TYPE
notifications: [Notification]
createdAt: DateTime
}
type Video {
channel: Channel
...
}
type Channel {
subscribers: [User]
}
extend type Mutation {
releaseVideo(id: ID!): VideoReleaseResult # generates an event of type VIDEO_RELEASED, and passes in the channel name for purposes of constructing the notification message
}
type VideoReseaseResult {
success: Boolean!
event: Event!
}
Thanks @kevin-lindsay-1 for the insights. The way I have it setup is that a user will only change the watched
state of their user-notification relation record. So they will not interact with the actual notification that’s shared between users.
situation A (current setup):
Sally has 100 followers. She reviews a movie. 1 notification record is created in the _Notification
table. 100 records are created in the _NotificationToUser
table and each user has a reference added to their _User
table.
situation B (proposed setup):
Sally has a 100 followers. She reviews a movie. 1 notification record is created in each of her followers _User
table.
Looks like situation B is better since it won’t create a endless amount of relation and allows to query notifications directly on the user so there’s no need to look through the notifications relationship table.
Thanks!
1 Like