tk2232
October 26, 2021, 10:22am
1
I am trying to implement a chat in my app and having difficulties with the scheme.
I wanted to add the following to the normal chat functionality:
There should be a group chat.
It should be shown who read the message and when.
If someone is typing this should be displayed.
My idea so far was the following scheme:
Class Chat
{groupName (String), author (pointer: User), members (relation: User), messages (relation: ChatMessages), isGroupChat (bool)}
The question I am asking myself is, should I set a relation to messages or is it better to just set a pointer in the ChatMessages class to Chat? `
Class ChatMessages
{chat (pointer: Chat), message (String), readBy (relation: ChatReadBy)}
Same question here. Set a pointer or simply a pointer / relation from Chat to ChatMessages?
Class ChatReadBy
{user (pointer: User), createdAt (Date)}
Then the question remains, where do I put isTyping?
And the most important question, does the scheme I have set up make sense at all?
Since many have probably already implemented a chat functionality, I hope that you can help me or give a few tips.
uzaysan
October 26, 2021, 10:33am
2
İn order parse server to notify clients, an object needs to be created or updated which is not necessary for live who is typing feature imo. But quick workaround for that would be, since parse server work with express, you can implement socket.io with your express app and use that for live who is typing feature without saving anything to database and for the rest you continue to use parse server.
tk2232
October 26, 2021, 10:37am
3
Ok thanks, I also thought of socket.io . I thought there might be a function that I might have overlooked in Parse
tk2232
November 11, 2021, 10:28pm
4
So far I have tried the following scheme, but unfortunately I am not satisfied with it. There have to be a lot of cloud code queries to check the permissions.
Chat
{cretor (pointer: User) members (relation: User) isGroupChat (bool) groupName (String)}
ChatMessage
{author (pointer: User) message (String) offlineId (String) chat (pointer: Chat)}
I use the offlineId for GraphQL optimistic caching.
Does it make more sense to set a role for every chat? Are there disadvantages to assigning many roles?
Is there a possibility in cloud code to check whether the user is present in the relation members of chat? That’s how I’ve tried it so far.
Parse.Cloud.beforeFind("ChatMessage", async (req) => {
if (req.master) return req.query;
const query = req.query;
const user = req.user;
const publicUser = await findUserPublic(user.get("username"));
const results = await query.find({useMasterKey: true});
if (results === undefined || results.length === 0) return query;
if (results[0].get("chat") !== undefined) {
const chat = await results[0].get("chat").fetch({useMasterKey: true});
const members = await chat.relation("members").query().find({useMasterKey: true});
let isIn = false;
for (const member of members) {
if (member.id === publicUser.id) {
isIn = true;
break;
}
}
if (!isIn) throw "Not allowed";
} else {
throw 'Nothing found';
}
return query;
}, {
requireUser: true,
});
I have one more question, does include not work with GraphQL queries in cloud code?
This query returns results[0].get(“chat”) = undefined even if I add query.include(‘chat’)
query GetLastChatMessage($chatId: ID!) {
chatMessages(
where: { chat: { have: { objectId: { equalTo: $chatId } } } }
last: 1
) {
edges {
node {
message
author {
...PublicUserFragmentCore
}
}
}
}
}
fragment PublicUserFragmentCore on UserPublic {
__typename
objectId
photoURL
username
}
But this works
query GetLastChatMessage($chatId: ID!) {
chatMessages(
where: { chat: { have: { objectId: { equalTo: $chatId } } } }
last: 1
) {
edges {
node {
message
chat {
objectId
}
author {
...PublicUserFragmentCore
}
}
}
}
}
fragment PublicUserFragmentCore on UserPublic {
__typename
objectId
photoURL
username
}
tk2232
November 12, 2021, 11:50am
5
Ok I saw in the documentation that I can simplify the beforeFind function significantly with matchesQuery
Parse.Cloud.beforeFind("ChatMessage", async (req) => {
if (req.master) return req.query;
const query = req.query;
const user = req.user;
const publicUser = await findUserPublic(user.get("username"));
const chatQuery = new Parse.Query('Chat');
chatQuery.equalTo('members', publicUser);
const messageQuery = new Parse.Query('ChatMessage');
messageQuery.matchesQuery('chat', chatQuery);
const newQuery = Parse.Query.and(query, messageQuery);
return newQuery;
}, {
requireUser: true,
});