Firebase data schema guidance - firebase

I am newbie to Firebase and working on to create events using firebase. Here i am inviting my friends using their phone number.(It is not necessary that whom i am inviting will be part of the system user.)
Below is my schema:
{
"events": [
{
"message": "Lunch",
"startTime": 1469471400000,
"eventCreatorId": 1,
"endTime": 1469471400000,
"invitees": [
{
"phone": "1234567890",
"type": "phone"
},
{
"phone": "345678901",
"type": "phone"
}
]
}
]
}
Now problem is that how i can find list of all events for specific invites?? (i.e in above case i want to find list of all events for user with phone number eqaul to 345678901.)
Can anyone suggest good schema to handle above scenario with firebase?

Welcome to using a NoSQL database. :-)
In NoSQL you often end up modeling the data different, to allow the queries that you want your app to execute. In this case, you apparently want to both show the invitees per event and the events per invitee. If that is the case, you'll store the data in both formats:
{
"events": {
"event1": {
"message": "Lunch",
"startTime": 1469471400000,
"eventCreatorId": 1,
"endTime": 1469471400000,
"invitees": {
"phone_1234567890": true,
"phone_345678901": true
}
}
},
"users": {
"phone_1234567890": {
"phone": "1234567890",
"type": "phone",
"events": {
"event1": true
}
},
"phone_345678901": {
"phone": "345678901",
"type": "phone"
"events": {
"event1": true
}
}
}
}
You'll see that I've split your data into two separate top-level nodes: events and users. They refer to each other with so-called explicit indexes, essentially a set of foreign keys that you manage (and join) in your client-side code.
I've also replaced you arrays with named keys. If your events/users have natural keys (such as uid for identifying the user if you happen to use Firebase Authentication) you'd use that for the key. But otherwise, you can use Firebase push ids. Using such keys leads to a more scalable data structure then depending on array indices.
Both of these topics are covered in the Firebase documentation on data structuring. I also highly recommend this article on NoSQL data modeling.

Related

How can document references be used for Firestore API's [runQuery.startAt]?

When using the Firestore REST API to order and filter results, I am unable to use a cursor/reference value for the startAt value. I feel this may be possible, seeing it is provided in examples of Firestore's cursor-based pagination is detailed in their SDK: https://firebase.google.com/docs/firestore/query-data/query-cursors
I have a query that uses orderBy on a integer field within a document. I can successfully start at a specific integer value for this query, like so:
"structuredQuery": {
"from": [
{
"collectionId": "objects"
}
],
"orderBy": [
{
"field": {
"fieldPath": "counter"
},
"direction": "DESCENDING"
}
],
"startAt": {
"values": [
{
"integerValue": 15
}
]
}
}
I'm hoping to benefit from cursor pagination, but unfortunately if I change the startAt value to referenceValue, the query results do not reflect this, even though the query is successfully performed.
"startAt": {
"values": [
{
"referenceValue": "projects/.../databases/(default)/documents/objects/OjvmBvvQ9TkyyQiJ4ExJ"
}
]
}
Am I missing something in the way this works differently to the SDK examples?
Note that it's not a document reference but a document snapshot that you can use as a query cursor. A snapshot includes the field values needed for startAt. The SDKs take a document snapshot, extract the field values, and pass those values to startAt.
You can see the Node.js client library doing this here in createCursor and extractFieldValues.

Storing data on Firebase to be queried later

We have an application that will store data on Firebase (database) that will then be queried later.
What is the correct format to store the data in.
The example data will be completedGames. They will have data such as:
UserId
TimeToComplete
GameData
Etc...
The query later will then look for all completed games by UserId. We want to ensure the data is collected in the best way possible to query later, rather than refactoring later.
In your case, first off - be sure you have a good reason to use Firebase over Firestore. Once you're confident you should stick with Firebase Realtime Database, look at the below excerpt of documentation. So, you might actually have 2 separate parent nodes, 1 for userId and another for games. Each game node's child is a particular game, which has a child tree of game users (by userId).
Flatten data
structures
If the data is instead split into separate paths, also called
denormalization, it can be efficiently downloaded in separate calls,
as it is needed. Consider this flattened structure:
{
// Chats contains only meta info about each conversation
// stored under the chats's unique ID
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
},
// Conversation members are easily accessible
// and stored by chat conversation ID
"members": {
// we'll talk about indices like this below
"one": {
"ghopper": true,
"alovelace": true,
"eclarke": true
},
"two": { ... },
"three": { ... }
},
// Messages are separate from data we may want to iterate quickly
// but still easily paginated and queried, and organized by chat
// conversation ID
"messages": {
"one": {
"m1": {
"name": "eclarke",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... },
"m3": { ... }
},
"two": { ... },
"three": { ... }
}
}

Firebase database data aggregation

Let's take a look at "Instagram-like" app, as an example.
In the feed we got posts, with user avatar and name at the top, photo or video below, and last comments, likes count and post time at the bottom.
Basically, at the client I'm waiting to get from backend something like
{
username: "John",
avatar:"some_link",
photo:"photo_url",
likes:"9",
time:"182937428",
comments:[comments there]
}
but using Firebase, I need to store data in more flat way. so there will be "users", "posts" and "comments" in data JSON.
How am I suppose to aggregate data from those nodes in some kind of single object, which is easy to use at client?
Or should I ask Firebase for posts, than for all users in it, and for all their comments, and do aggregation after all three 'requests' are done?
You should implement "shallow" tree structure, and use references where needed.
That means that for most cases in your app you should use the object as at is, Making sure that it contain the "essential data" (in the example below "the chat title"), and keys for "further" information (in the example, keys to the "members").
from firebase docs (https://firebase.google.com/docs/database/web/structure-data):
bad
{
// This is a poorly nested data architecture, because iterating the children
// of the "chats" node to get a list of conversation titles requires
// potentially downloading hundreds of megabytes of messages
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"messages": {
"m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
"m2": { ... },
// a very long list of messages
}
},
"two": { ... }
}
}
good
{
// Chats contains only meta info about each conversation
// stored under the chats's unique ID
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
},
// Conversation members are easily accessible
// and stored by chat conversation ID
"members": {
// we'll talk about indices like this below
"one": {
"ghopper": true,
"alovelace": true,
"eclarke": true
},
"two": { ... },
"three": { ... }
},
// Messages are separate from data we may want to iterate quickly
// but still easily paginated and queried, and organized by chat
// conversation ID
"messages": {
"one": {
"m1": {
"name": "eclarke",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... },
"m3": { ... }
},
"two": { ... },
"three": { ... }
}
}

Is this NoSql schema correct?

I start to use Firebase and NoSql, I'd like to understand best practice, so I try to create this schema with orders, order_rows and articles. The main query is to show specific order so I create this:
{
"orders": {
"1": {
"date": "1/1/2016",
"row_order": {
"1": true,
"2": true
}
},
"2": {
"date": "1/1/2016",
"row_order": {
"3": true
}
}
},
"articles": {
"1": {
"name": "a"
},
"2": {
"name": "b"
}
},
"row_orders": {
"1": {
"quantity": 7,
"id_article": 1
},
"2": {
"quantity": 2,
"id_article": 2
},
"3": {
"quantity": 4,
"id_article": 2
}
}
}
When I must show order number 1, I can find order rows and then from row orders detect articles.
I don't use classic sql schema (row_orders with id_article and id_order) to semplify get data.
Is this correct? Or How I can do?
There is no way to say of a NoSQL data structure is correct. If you want to learn about NoSQL, I recommend reading the Firebase documentation on structuring data, this article on NoSQL data modeling and some of the older blog posts on the Firebase blog (such as this one).
One immediate problem in your data structure is that you use pseudo array-indices as the keys for your data. These will lead to a hard time, since Firebase will try to interpret them as actual array indices (meaning you get back an array with an empty first element) and it doesn't scale over many users or users who may be offline. Read more about this in the blog post on arrays.

Filtering Firebase lists based nested child keys?

In the Firebase docs for Structuring Data, they give the follow data structure as an example of mapping users to groups.
{
"users": {
"alovelace": {
"name": "Ada Lovelace",
// Index Ada's groups in her profile
"groups": {
// the value here doesn't matter, just that the key exists
"techpioneers": true,
"womentechmakers": true
}
},
...
},
"groups": {
"techpioneers": {
"name": "Historical Tech Pioneers",
"members": {
"alovelace": true,
"ghopper": true,
"eclarke": true
}
},
...
}
}
With that structure, how would I go about querying only groups with a specific member? So only groups where alovelace is a member, for example.
Would I do this with a rule? If so, what would that rule look like?
OrderByChild works in this case - below the query object
angularfire.database.list('.../groups', {
query: {
orderByChild: 'members/alovelace'+,
startAt: true
}
});
Not sure how the performance is compared to the answer by Frank van Puffelen - might be worse even since it's another list query rather than just a few direct object lookups.
That information is already in the data model. Right under /users/alovelace/groups you have a list of the groups she's a member off.
The reason for recommending this model is that it doesn't even require a query to load the list of groups, it just requires a direct-access read of /users/alovelace/groups.

Resources