Android - Firebase Database Structure - android

I am developing an android application where older kids can pick up younger kids and walk to school. With the application the authenticated (email and password) younger kid can choose between three adresses to get picked up. As of right now my realtime database looks like this:
Should I make a new node named "Adresses" and have a structure like this below?
Adresses
Sherman Street
username: Jannie
Because I want to retrieve the name of the street and all the users that have chosen the adress in a listview

Your suggested method is good practice: you should try to flatten your data structure as much as possible.
I'd suggest using the user's ID for the membership of each address so it's easy to identify though. This way you can obtain a list of the members of "Sherman Street" from /addresses/Sherman Street and then match the keys listed within there to the users at /users/ with ease.
{
"users": {
"oXrJPVZsnMP3VKp9palSBfdnntk1": { ... },
"xQDx3ntavhV3c02KFRPS8lxYfC62": { ... }
},
"addresses": {
"Sherman Street": {
"members": {
"xQDx3ntavhV3c02KFRPS8lxYfC62": true
}
},
"Wallaby Way": {
"members": {
"oXrJPVZsnMP3VKp9palSBfdnntk1": true
}
}
}
}
You can also add backwards linking too by adding an address field to the user which matches the address name:
{
"users": {
"oXrJPVZsnMP3VKp9palSBfdnntk1": { ... },
"xQDx3ntavhV3c02KFRPS8lxYfC62": {
"username": "Jannie",
"address": "Sherman Street"
}
},
"addresses": {
"Sherman Street": { ... }
}
}
Using both together makes it easy to identify what users have selected which addresses, irrespective of which object you are currently handling within the app.
See the Firebase documentation on database structure for further details on structuring your data like this.

Related

Query Data from Google Spreadsheet in Android

I am trying to query data form Google Spreadsheet available to be read by anyone with the Read Only link.
I implemented this Quickstart solution but here is what I need:
Access data just with URL, no authentication needed
Query item in column A and get value in column B
No need for updating any data
I tried constructing queries like:
http://spreadsheets.google.com/tq?tq=SELECT%20*%20WHERE%20A=C298732300456446&key=2aEqgR1CDJF5Luib-uTL0yKLuDjcTm0pOIZeCf9Sr0wAL0yK
But all I get is:
/*O_o*/
google.visualization.Query.setResponse(
{
"version": "0.6",
"reqId": "0",
"status": "error",
"errors": [
{
"reason": "invalid_query",
"message": "INVALID_QUERY",
"detailed_message": "Invalid query: NO_COLUMN: C298732300456446"
}
]
}
This comes when the data is actually present in the sheet in column A with value C298732300456446.
What can I do for getting the data, without any authentication from my spreadsheet?
I am not sure if this can be done. If fine, I can suggest an alternative solution. You can try writing a Google App script like:
function doGet(e) { return getInfo(e); }
function doPost(e) { return getInfo(e); }
function getInfo(request) {
var someValueFromUrl = request.parameter.value;
var requiredValue = "";
var sheet = SpreadsheetApp.openById("spreadsheet_id");
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
Logger.log("Reading row num: " + i);
if(data[i][0] == someValueFromUrl) {
requiredValue = data[i][1];
break;
}
}
Logger.log(requiredValue);
return ContentService.createTextOutput(JSON.stringify(requiredValue));
}
This way, you can publish this script as web app and call it using an URL which will be obtained when you publish this script.
Call the script like:
https://script.google.com/macros/s/obtained_url/exec?value=1234
If key is found, you will get the String response as:
"value"
I hope this helps.
C298732300456446 needs to be put within single quotes.
So you need to enclose C298732300456446 as %27C298732300456446%27
Your'e modified query would be
http://spreadsheets.google.com/tq?tq=SELECT%20*%20WHERE%20A=%27C298732300456446%27&key=2aEqgR1CDJF5Luib-uTL0yKLuDjcTm0pOIZeCf9Sr0wAL0yK
I'm unable to test this though - looks like you've removed/removed access from this spreadsheet.

Rule entries duplicates firebase not working

I have an application in android that registers sellers, which have a unique email, I am storing them in firebase. Create a rule to not allow duplicates to be added but it does not seem to work. What am I doing wrong?
{
"rules": {
".read": true,
".write": true,
"sellers": {
"$seller": {
"email": {
".write": "!data.exists()"
}
}
}
}
}
my method to add
public void addSeller(Seller seller){
HashMap<String,Seller> map= new HashMap<>() ;
String email = seller.getEmail().replace(".",",");
map.put(email,seler);
database.child("sellers").setValue(map);
}
You're calling push(), which generates a new child that is statistically guaranteed to be unique.
If you want to ensure unique email addresses, you will have to keep a collection where the (encoded) email addresses are the keys:
emails
pete#somedomain,com
puf#somedomain,com
With this structure, the following rule will work to ensure an email address can only be written once:
{
"rules": {
".read": true,
"emails": {
"$email": {
".write": "!data.exists()"
}
}
}
}
The topic of unique values comes up regularly, so I recommend you also check out these:
Firebase android : make username unique
How do you prevent duplicate user properties in Firebase?
Enforcing unique usernames with Firebase simplelogin
unique property in Firebase
Firebase Unique Value
What Firebase rule will prevent duplicates in a collection based on other fields?

How to paginate in Firebase Database #AskFirebase

I am creating an application that is some kind of a personal vocabulary. The database is of the following form.
Now I need to implement a pagination, partial retrieval of the words of a user, but preserving the lexicographical order. Keeping words as keys (/user/{uid}/words/{word}) is not suitable, because handling homographs will be impossible in the future (as their key will coincide). I decided to keep additional property word for each user, so that I can call db.getReference().child("users").child(uid).child("words").orderByChild("word").
This will retrieve all words of a user. Now I need to paginate this query, e.g. first download 20 words and then again 20 etc., but preserving lexicographical order.
{
"users" : {
"yXYSqB016JMr1FIc85pvMbvqDDt2" : {
"words" : {
"5v1a1PaDKnTvvOH19kaFTa1iyOx2" : {
"index" : 1,
"word" : "apple"
},
"kXHakBKxk9TrAlWL1vTOCe0akk80" : {
"index" : 2,
"word" : "house"
},
"xSKSqB312JMrsFig15pvMbvqAAt0" : { ... }
}
},
"zCAtMpl9uxSjG9dJarGktTTs20w2" : { ... }
},
"vocabulary" : {
"en" : {
"5v1a1PaDKnTvvOH19kaFTa1iyOx2" : {
"definitions" : {
"a fruit that grows on a tree" : true
},
"word" : "apple"
},
"kXHakBKxk9TrAlWL1vTOCe0akk80" : { ... },
"xSKSqB312JMrsFig15pvMbvqAAt0" : { ... }
}
}
}
You seem to come from a SQL way of thinking, where you paginate by specifying the number of items to get and the number of items to skip. This is index-based pagination.
Firebase on the other uses cursor-based pagination. You tell it the nimber of items to get and at which item to start (or end). You identify this item by the value of the property on which you order, in your case that is the value of word. Since the same value could potentially appear in multiple children, you can also specify the key (the thing starting with 5v1a1...) of the child at which to start/end as a second parameter.
So say that you have a page size of two. You get the first 2 words with:
DatabaseReference allWords = db.getReference().child("users").child(uid).child("words");
Query firstPage = allWords.orderByChild("word").limitToFirst(2);
When you attach a listener to this, you'll get the first two words. You'll need to remember the word and the key of the last word in this first page:
String lastWordOnPreviousPage = "house";
String lastKeyOnPreviousPage = "5v1a1...";
Now if you need the second page of two words, you get them by:
Query secondPage = allWords.orderByChild("word").startAt(lastWordOnPreviousPage, lastKeyOnPreviousPage).limitToFirst(2);

How to implement ondelete cascade in Firebase (Android)

I am new with Firebase. I want to implement ondelete cascade in Firebase.
Here is the problem for which I want solution
I have two table "users" and "groups".
{ "users":{
"user1":{
"username":"john",
"full_name":"John Vincent",
"created_at":"9th Feb 2015",
"groups":{
"group1":true,
"group3":true
}
"last_logins":...
},
"user2": ...,
"user3": ...
}"groups": {
"group1"{
"group_name":"Administrators",
"group_description":"Users who can do anything!",
"no_of_users":2,
"members":{
"user1":true,
"user3":true
}
},
"group2"{
"group_name":"Moderators",
"group_description":"Users who can only moderate!",
"no_of_users":1,
"members":{
"user2":true
}
}
}
}
Please pardon me for above code indentation.
Now if I removed user1 from users table then how it should be automatically removed from groups table using Firebase.
This can easily done using SQL but I don't know how to do this in Firebase. One way to do this in Firebase is to remove user1 from users and then makes group1 and group3 to null and then in groups table make user1 to null under group1/member but this need 2-3 calls. So is there any another best way to do this.
Please help me I am stuck here.
The Firebase Database has no knowledge of relations between values in its JSON tree. In SQL/relations terms: it doesn't have the concept of foreign keys. This means that it also doesn't have an option to delete related objects with a cascading delete. You will need to delete each value separately.
But you can combine all those deletes into a single call by using multi-location updates. If you write null to each of the locations for the user, you can delete all of them with one call to updateChildren():
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Map<String,Object updates = new HashMap<String,Object>();
updates.put("users/user1", null);
updates.put("groups/group1/members/user", null);
// Do a deep-path update
ref.updateChildren(updatedUserData, new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
System.out.println("Error updating data: " + firebaseError.getMessage());
}
}
})
With this in place, you could then write security rules that validate that members of a group must also exist under the /users node:
{
"rules": {
"groups":
"$groupid": {
"users": {
"$uid": {
".validate": "newData.parent().parent().parent().parent().child('users').hasChild($uid)"
}
}
}
}
}
}
The validation rule is a bit easier to understand if you read the multiple .parent() calls as newRoot (which unfortunately doesn't exist). So in pseudo-code it is:
newRoot.child('users').hasChild($uid)
In words: a UID can only be a member of a group if it also exists under /users.

Firestore structure model

Coming from SQL background and watching tutorials, I am trying to do a model in Firestore to understand how things work. I basically wants model a situation where user has multiple lists and every list has his friends ( to display names of friends). Does the below make sense?
Users
"john#xyz.com"
-Name: John Smith
"celina#xyz.com"
- Name: Celina West
"dan#xyz.com"
- Name: Dan Nelson
Lists
"john#xyz.com"
List_Titles
"List 1"
- <AutoGenId>: Celina West
- <AutoGenId>: Dan Nelson
anything with "-" is a field, anything with bracket it Document and anything without prefixes is collection.
One issue I find here, is that lets say a user updates his/her name. Then I have to go not to only Users Collection but through every subcollection List to look for that person and update name. I thought about using email ID instead of name but then that goes against the "structure the nosql db as you view it" way. Plus then everytime I have to hit the Users tables in a seperate call for every Id to query the name.
Is my assumption correct?
Thanks
Snake, there is no perfect database structure. You need to model your database so you can query very easily later, when you need to do CRUD operations. In one of my tutorials, I have explained step by step how can we structure a Firestore database which holds users, lists and products.
Please see the below database structure that can help achieve what you want.
{
"users": {
"appfirstuser#gmail.com": {
"tokenId": "eGVzwv7Y...",
"userEmail": "appfirstuser#gmail.com",
"userName": "First User"
},
"appseconduser#gmail,com": {
"tokenId": "cc8Uhriu...",
"userEmail": "appseconduser#gmail.com",
"userName": "Second User"
}
},
"shoppingLists": {
"appfirstuser#gmail.com": {
"userShoppingLists": {
"3Oe37QdcHXSohL2dnNlX": {
"createdBy": "First User",
"date": "February 3, 2018 at 2:56:31 PM UTC+2",
"shoppingListId": "3Oe37QdcHXSohL2dnNlX",
"shoppingListName": "Pharmacy"
},
" WovuleVbTZdql68gXk84": {
"createdBy": "First User",
"date": "February 3, 2018 at 2:56:20 PM UTC+2",
"shoppingListId": "WovuleVbTZdql68gXk84",
"shoppingListName": "Grocery"
}
}
}
},
"products": {
"WovuleVbTZdql68gXk84": {
"shoppingListProducts": {
"8vinaHJyjG4JqFH33YE7": {
"productId": "8vinaHJyjG4JqFH33YE7",
"productName": "Milk"
},
"JALygtedMHWQcdEoSnPM": {
"productId": "JALygtedMHWQcdEoSnPM",
"productName": "Eggs"
},
"WFkJMWZSnhJU9iwGeoOi": {
"productId": "WFkJMWZSnhJU9iwGeoOi",
"productName": "Bacon"
}
}
}
}
}
Using a database structure that looks like this, you'll be abte to create, read, update and delete records very easily.

Categories

Resources