Firebase data structure for one to chat app or private - javascript

Currently I am developing a web applications where i need to add chat functionality. A user publish his product, and another user interested can chat with the seller to stay or know more details about product.
I got stuck on implantation of chat, I can't find out a suitable data structure for need.
My need is; let's say John is the seller and publish his phone to sell. Charles got interest on John phone's and he want to know more details about that, so start chatting with John. They don't know each other before chatting, not like WhatsApp. Where a user know another user before send a message.
John could have published so many products and Charles could interest on different products of him, for each product will create a new conversation (chat).
I want that, if john delete a message, then that should delete from his chat not from Charles.
The chat is private or one to one.
Until now i have done this data structure. I don't know if it is the best way? please suggest me
chats
sender_ID _ Reciever_id
product_id
message:''
Timestamp:''
SenderName:''

When a user publishes a product (the potential seller), you'll need to associate their user ID with that product. Based on that, the interested user (potential buyer) can make the connection.
Given your other requirements, I'd nest the chats:
chats: {
uid1_uid2_productid: {
pushid: { message: ..., timestamp: ..., sender: ... },
pushid: { message: ..., timestamp: ..., sender: ... }
}
}
And then associate these chats with the correct users in user-specific lists:
user_chats: {
uid1: {
uid1_uid2_productid: true
},
uid2: {
uid1_uid2_productid: true
}
}
Instead of true you could also store a value (or more properties) that help you display the list of chats for that specific user.
If you want each user to have a completely separate copy of the chat/room, your easiest approach is to duplicate the rooms. So:
chats: {
uid1_uid2_productid: {
pushid: { message: ..., timestamp: ..., sender: ... },
pushid: { message: ..., timestamp: ..., sender: ... }
}
uid2_uid1_productid: {
pushid: { message: ..., timestamp: ..., sender: ... },
pushid: { message: ..., timestamp: ..., sender: ... }
}
}
And then:
user_chats: {
uid1: {
uid1_uid2_productid: true
},
uid2: {
uid2_uid1_productid: true
}
}

Related

Disconnecting Many-to-Many Relationships in Prisma + MySQL

I am so completely lost. I have an explicit many to many relation: Users can have multiple Lists, but lists can be owned by multiple users:
model List {
id String #id #default(cuid())
title String
users UsersOnLists[]
}
model User {
id String #id #default(cuid())
name String
lists UsersOnLists[]
}
model UsersOnLists {
id String #id #default(cuid())
order Int
user DictItem? #relation(fields: [userId], references: [id])
userId String?
list List? #relation(fields: [ListId], references: [id])
listId String?
}
Now I'd like to connect a list to a user:
prisma.list.update({
where: {
id: input.id
},
data: {
users: {
create: [{
order: 123,
user: {
connect: {
id: "abcd-123",
}
}
}],
}
}
});
This works.
However, I don't know how to go about disconnecting many-to-many relations in prisma? Say I want to disconnect the user again from the list? How would I do this?
prisma.list.update({
where: {
id: input.id
},
data: {
users: {
disconnect: [{
user: {
disconnect: {
id: "abcd-123",
}
}
}],
}
}
});
This doesn't work.
I also can't find much in the prisma docs about disconnecting. Any ideas?
I guess I could jus delete the row from the Relations-Table, but this doesn't feel as clean and I guess I would still have the old ids in the user & list tables? I would prefer using disconnect, if this is the recommended method for that.
Are you getting a specific error? If you are using a code editor/IDE with TypeScript hinting, it should be giving you a specific error(s) about what's going on. If not that, then the command line should be giving you errors when you attempt to run an operation.
Docs: https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#disconnect-a-related-record
The "disconnect" operation cannot disconnect deeply-nested relations. It only disconnects documents directly connected to the model in question. In your situation, you can only disconnect a UserOnList from a List, but you cannot also disconnect User from UserOnList in the same operation.
prisma.list.update({
where: {
id: input.id
},
data: {
users: {
disconnect: [{
id: "ID_OF_UsersInList_MODEL_HERE"
}],
}
}
});
Also - you don't need the UsersInList table. Prisma can manage the "join" table under the hood for you if you don't need any extra information or data on that model. Check out the docs here if you want Prisma to manage this table on its own: https://www.prisma.io/docs/concepts/components/prisma-schema/relations/many-to-many-relations

Graphql schema code to view user profiles

Am new to Graphql and actually following a tutorial. I am building a project in React Native and using AWS Amplify and Graphql for my backend. I needed a little change from the tutorial am following, I want users to be able to view user profile of other users in a their contact list just Instagram or Facebook.
In my schema.graphql I have the following code:
type User #model {
id: ID!
name: String!
imageUri: String
username: String!
email: String!
}
But I don't know the next code to write for user profile and the relationships for users to view other user user profiles.
I have been able to list contacts with the following code:
useEffect(() => {
const fetchUsers = async () => {
try {
const usersData = await API.graphql(
graphqlOperation(
listUsers
)
)
setUsers(usersData.data.listUsers.items);
} catch (e) {
console.log(e);
}
}
fetchUsers();
}, [])
Please I need guide on how to achieve viewing user profile when user is clicked on the contact list.
you have to add "auth" rule to your model
type User #model
#auth(
rules: [
#this is for logged-in user. cognito user is default for provider
# In order to prevent private users from creating, another rule must be set for creating
{ allow: private, operations: [read] }
# default provider is cognito
{ allow: private, provider: iam, operations: [read, create, update, delete] }
# Only Owner can update its own data
{ allow: owner, ownerField: "username", operations: [update] }
]
) {
id: ID!
name: String!
imageUri: String
username: String!
email: String!
}
In the above code, I defined two auth rules. One is for Cognito user, he can only read, another one for the "iam" user who has more privileges.

In what form to keep a chat list and their messages in client side

I have 2 options for storing the received data
1.
[
{
chatId: 'chatId1',
author: 'authorId1',
members: [],
messages: []
},
{
chatId: 'chatId2',
author: 'authorId2',
members: [],
messages: []
},
...
]
2.
{
'chatId1': {
author: 'authorId1',
members: [],
messages: []
},
'chatId2': {
author: 'authorId2',
members: [],
messages: []
},
...
}
In the first option, to add a message in chat with the chatId2 ID, I have to loop and find the missing chat, but in the second option, I can get the chatId2 property of an object.
What form do you recommend?
P.S. Sorry for my English. Thanks ;)
It depends on what you need to do, size of the data, requirements, etc.
You can easily combine these options by keeping the id field and looping though values if needed. But depending on your tasks you may also need to add additional sorting then.

Firebase nested queries slow - sendRequest call when we're not connected not allowed

I want to implement a follow system between users.
For that, I want to display all of the 250 users of my app, then add a checkmark button next to the ones I already follow, and an empty button next to the ones I do not follow.
var usersRef = firebase.database().ref(‘/users’);
var followingRef = firebase.database().ref(‘/followingByUser’);
var displayedUsers = [];
// I loop through all users of my app
usersRef.once('value', users => {
users.forEach(user => {
// For each user, I check if I already follow him or not
followingRef.child(myUid).child(user.key).once('value', follow => {
if (follow.val()) {
// I do follow this user, follow button is on
displayedUsers.push({
name: user.val().name,
following: true
});
} else {
// I do not follow this user, follow button is off
displayedUsers.push({
name: user.val().name,
following: false
});
}
})
})
})
When doing that, I often (not always) get the following error: "Error: Firebase Database (4.1.3) INTERNAL ASSERT FAILED: sendRequest call when we're not connected not allowed."

Eventually, all the data is fetched, but after 10 seconds instead of 1 (without the error).
I do not believe it is an internet connection issue, as I have a very fast and stable wifi.
Is it a bad practice to nest queries like that?
If not, why do I get this error?
My data is structured as below:
users: {
userId1: {
name: User 1,
email: email#exemple.com,
avatar: url.com
},
userId2: {
name: User 2,
email: email#exemple.com,
avatar: url.com
},
...
}
followByUser: {
userId1: {
userId2: true,
userId10: true,
userId223: true
},
userId2: {
userId23: true,
userId100: true,
userId203: true
},
...
}
Your current database structure allows you to efficiently look up who each user is following. As you've found out it does not allow you to look who a user is follow by. If you also want to allow an efficient lookup of the latter, you should add additional data to your model:
followedByUser: {
userId2: {
userId1: true,
}
userId10: {
userId1: true,
},
userId223: {
userId1: true,
},
...
}
This is a quite common pattern in Firebase and other NoSQL databases: you often expand your data model to allow the use-cases that your app needs.
Also see my explanation on modeling many-to-many relations and the AskFirebase video on the same topic.

Rooms/Channels and userId in Meteor.js

I'm building a multiplayer, turn-based game using meteor.js. The application will handle multiple games, so I'd like to separate my users into rooms.
I've done it before using socket.io channels, but I'm struggling to understand how it should be done in Meteor.
The flow I'd like to achieve is:
User visits http://localhost:3000/join/userId
I make a server-side call to an external API using "sessionId" as parameter, getting user's userId, his assigned roomId and an array of allowed userId's for this room
I'd like to create a room with roomId for the user or join him to an existing one. I know I should create a 'Rooms' collection, but I don't know how to tie users to my rooms and publish messages only to those present in the given room.
I'd like to avoid using 'accounts' package, because I don't need authorisation on my side - it'll be handled by step #2 mentioned above - but if the easiest and cleanest way of doing it involves adding this package, I can change my mind.
Your Rooms collection could look like:
{
_id: "<auto-generated>",
roomId: "roomId",
users: [ "user1", "user2", "user3", ... ],
messages: [
{ message: "", userId: "" },
{ message: "", userId: "" },
{ message: "", userId: "" },
...
]
}
The server-side API call returns
userId and roomId among other information.
So you can do a
Rooms.update({ roomId: roomId }, { $push: { users: userId } }, { upsert: true });
This would push the user into the exiting room or create a new room and add the user.
Your publish function could look like:
Meteor.publish("room", function(roomId) {
// Since you are not using accounts package, you will have to get the userId using the sessionId that you've specified or some other way.
// Let us assume your function getUserId does just that.
userId: getUserId( sessionId );
return Rooms.find({ roomId: roomId, users: userId });
// Only the room's users will get the data now.
});
Hope this helps.

Categories