Firebase database structure for one-on-one messaging? - firebase

I'm relatively new to Firebase and I'm trying to figure out the best way to structure my DB for 1:1 chats.
It basically has to function like Whatsapp - you have your active conversations on the left when a person sends a message that conversation is then put on top of the list and a basic one-on-one chat on the right.
Right now the best that I have got is to create a firestore "chats" collection
chats : {
chat : { users : [user_id, user_id], messages : {user_id, message, created_at} created_at }
}
Would this solution allow me to :
Get all the chats based on the logged-in user?
Then Sort the returned chats by date?
Get the latest message from the messages collection for each returned chat?
On new message change the order of the chat and update the latest message?
And if all of that is doable would this be effective or is a there a better way?
Any help would be appreciated - thanks!

How would a logged in user be associated with any given chat they participated into?
Right now your structure doesn't seem to allow for an easy handling of this, given that "user_id" are nested within the chat document.
Personally, here's what I would do.
First I would create 2 collections, one called chats one called users.
users would have the following structure:
{"users": {
"userID_1": {
"name": "John",
"surname": "Smith",
"chats": [
"chatID_1",
"chatID_2",
"chatID_3"
]
},
"userID_2": {
"name": "Betty",
"surname": "Sue",
"chats": [
"chatID_1",
"chatID_4"
]
}
}}
Chats would instead be stored like this:
{"chats": {
"chatID_1": {
"chatName": "foo",
"otherInfo": "..",
"messages": {
"messageID_1": {"senderID": "..", "message": "..", "timestamp": 999},
"messageID_2": {"senderID": "..", "message": "..", "timestamp": 999}
}
},
"chatID_2": {
"chatName": "bar",
"otherInfo": "..",
"messages": {
...
}
}
}}
This way, when a user is logged in, you can easily fetch all his chats by querying users.userID.chats, and retrieve the content of any selected chat by querying chats.chatID.messages.

Related

Firebase db rule to prevent delete related to another node

Assume that we have two nodes: "items" and "sales". How can I write a firebase db rule to prevent any item being deleted if it is related in another node. If a user wants to delete ("items\i01") it should not give permission because it is a relation under ("sales\s01\i01")
"items": {
"i01": {
"name": "item1"
},
"i02": {
"name": "item2"
},
}
"sales": {
"s01": {
"itemKey": "i01",
"price": "45"
},
"s02": {
"itemKey": "i02",
"price": "60"
},
...
}
Security rules can check whether data exists at a known path, but cannot perform searches for data across (a branch of) the JSON tree. So in your current data structure, there is no way to prevent the deletion of the item based on it still being referenced.
The typical solution would be to add a data structure that you can check in security rules to see if the item is still referenced anywhere. This would pretty much be an inverse of your current sales node, which tracks the items in a sale. The inverse node would track the sales for any item:
"sales_per_item": {
"i01": {
"s01": true
},
"i02": {
"s02": true
}
}
You will need to make sure that this new structure (sometimes called an inverted index) is updated to say in sync with sales, both in code and in security rules.
With that in place, you can then prevent deletion of an item that still has references with:
{
"rules": {
"items": {
"$itemid": {
".write": "!newData.exists() && !newData.parent().parent().child('sales_per_item').child($itemid).exists()"
}
}
}
}
As an alternative, you can consider moving the deletion logic into a Cloud Function, where you can do the "check for orders with the item" in code, instead of in security rules.
I also recommend reading these:
How to write denormalized data in Firebase
Patterns for security with Firebase: combine rules with Cloud Functions for more flexibility
Patterns for security with Firebase: offload client work to Cloud Functions

Developing a news feed of a sns with Firebase(NoSQL)

I’m trying to develop an app which is a social network service with firebase. Everything is alright. But, I got stuck when I think about news feed feature. Sure, I can find the posts user by user. But it's not cool and inefficient. Or, there is another idea. Create news feed document for the user, and add someone's posts when user follows or someone writes a post. But it is also not that good.
How could I make news feed feature with Firebase(or NoSQL, whatever)? I really want to know how to make news feed with NoSQL.
Actually Firebase blog explained about this on here.
{
"timeline": {
"user2": {
"-K-zOrtjiCGe7tgRk8DG": {
"text": "I love emojis!",
"uid": "user1"
}
},
"user3": {
"-K-zOrtjiCGe7tgRk8DG": {
"text": "I love emojis!",
"uid": "user1"
}
}
},
"followers": {
"user1": {
"user2": true,
"user3": true
}
}
}
It calls "Fan-out" process. And it's kind broad topic for NoSQL database environment.

How to prevent malicious scripts writing to Firebase database?

I been reading firebase 3+ documentation for a while and I'm still wondering how to manage the following scenario regarding safety:
Let say I have a website for publishing local business like yellow pages in where everyone with an account can add new entries and edit the info of the existing ones with the following schema:
{
"businesses"": {
"62061635": {
"id": "62061635",
"name": "Cellphone store"
},
"66856728": {
"id": "66856728",
"name": "El Bambino restaurant"
}
}
}
If a user with a successful login write the following snipped in the developers console:
firebase.database().ref('/businesses/').once('value').then(function(snapshot) {
console.log(snapshot.val());
});
Practically all users could retrieve all the businesses info, that's not so drastic, but if instead of the above code the users use the following code:
var i=0;
while(i++ < 10) {
var id = generateRandomString();
firebase.database().ref('businesses/' + id).set({
id: id,
name: generateRandomString()
});
}
That's something I worry about, I know there are rules for database, but in this case where all users can add and edit the info, how can I prevent the users to run malicious scripts like the ones above?

Firebase permissions based on user's role

In my application I am supposed to have three kinds of roles:
Store: Can do whatever kind of reads and writes on anything bellow their owned key;
Customers: Can create their chat keys only underneath their designated store; Once a chat is created they can only push to the message child, on their own chats;
Attendants: Can only update chats which are designated to them, and insert under their messages tag.
The database is something similar to:
"$store_id": {
"owner": STORE_ID,
"chats": {
...
"$chat_id": {
"owner": COSTUMER,
"attendant": ATTENDANT,
"messages": {
"$message_id": {
"owner": CUSTOMER_ID
}
}
}
...
}
}
I can't figure out how I can achieve this behavior because:
If a permission is applied to a top level node, their children can't override it;
If someone crack into the database with valid credentials (i.e.: customers'), they can assume whatever role they want;
How this kind of issue is managed in Firebase?

Triggering smart campaign and getting 603

I am trying to use Marketo smart campaign to send email data.
What I do is:
1) get or create Lead with addresse email
2) trigger smart campaign I've created with this lead_id and a couple of tokens I created on the folder containing the campaign.
That is, I am sending POST to https://.mktorest.com/rest/v1/campaigns/5826/trigger.json?access_token= with body
{
"input": {
"leads": [
{
"id": 2034349
}
],
"tokens": [
{
"name": "{{my.subject}}",
"value": "subj"
},
{
"name": "{{my.message}}",
"value": "the text"
}
]
}
}
And I get the response:
{u'errors': [{u'message': u'Access denied', u'code': u'603'}], u'requestId': u'c8f5#14c79fae723', u'success': False}
I was trying token names without "{{" and "}}", without "my." - the same result. The campaign exist and has this ID.
What's wrong here?
The role of the Marketo API user that you're using needs the "Execute Campaign" permission, and your current user is probably missing that permission. Unfortunately you can't edit the existing role. You'll need to create a new role, check that permission, and possibly also create a new API User.

Resources