Firebase Database structure UID - firebase

I am asking myself if this kind of database structure is good, because of identifying the user with an PK AND putting the UID again under that PK. I dont know if that makes really sence or even more, could be dangerous?
{
"Users" : {
"7idb6ThWR8aqmnEHFao5GRCV1kI3" : {
"dPicture" : "https://firebasestorage.googleapis.com/v0/b/parkir-ngasal.appspot.com/o/Profile_images%2Fcropped1465266876.jpg?alt=media&token=44f83fdf-935a-4b3c-8138-561dcba2fca7",
"status" : "hi my name is erik",
"uid" : "7idb6ThWR8aqmnEHFao5GRCV1kI3",
"username" : "erik"
}
},
"posts" : {
"-KfsrGsY8TWb2wiMFtAq" : {
"dPicture" : "https://firebasestorage.googleapis.com/v0/b/parkir-ngasal.appspot.com/o/Profile_images%2Fcropped1465266876.jpg?alt=media&token=44f83fdf-935a-4b3c-8138-561dcba2fca7",
"image" : "https://firebasestorage.googleapis.com/v0/b/parkir-ngasal.appspot.com/o/Post_Images%2Fcropped1354055061.jpg?alt=media&token=77fbc9ed-4356-43c1-b7bb-9563300a8b7b",
"small_title" : "tes",
"summary" : "tes",
"title" : "tes",
"uid" : "7idb6ThWR8aqmnEHFao5GRCV1kI3",
"username" : "erik"
}
}
}

It's not dangerous. The security you set at the parent level traverses downward. From the Firebase docs:
.read and .write rules work from top-down, with shallower rules
overriding deeper rules. If a rule grants read or write permissions at
a particular path, then it also grants access to all child nodes under
it.
As to if it makes sense...that's up to you decide. While there's nothing wrong with duplicating the key inside the data structure, it's not needed. It's just as easy to retrieve the data from the key as it is from the payload.
const data = await firebase.database().ref(`/Users/`).once('value');
const users = _.map(data.val(), (val, key) => {
return {
userId: key,
val.username,
val.dPicture,
val.status
};
});

Related

How to set Firebase rules to allow only listed userid in a db to r/w in another database

How to set Firebase rules to allow only listed userid in a db (or a key or node or subset of a db) to r/w in another key/subset of the same database?
This link only mentioned of w/r of the same node/key/subset of a db.
What I want to set is for example the following db :
'SomeDB' : {
'ListOfUsers': {
'key1' : { 'key': 'key1', 'name' : 'name1' },
'key2' : { 'key' : 'key2', 'name':'name2'},
and so on...
},
{'SomethingForWR': 'Some Database'}
The rules should be read and write is only allowed for 'SomethingForWR' (which is part of 'SomeDB') if the 'auth.uid' is equal to one or one of the keys in 'ListOfUsers' (which is also part of 'SomeDB')
If you want to check if a key exists in ListOfUsers you can do so with:
root.child('ListOfUsers').child('keyYouWantToCheck').exists()
With that knowledge, your rule to allow a user access to SomethingForWR if their UID exists in ListOfUsers could be something like this:
{
"rules": {
...
"SomethingForWR": {
".read": "root.child('ListOfUsers').child(auth.uid).exists()"
}
}
}

Firebase rules to avoid Duplicate Entries

What are the firebase rules required to avoid duplicate entries in below users array at sList collection level
"sList" : {
"-KZawgegLrIyq9h6GSf8" : {
"name" : "Test",
"users" : [ "-KZawhnFZLcqFKNwZnSi", "-KZawhnFZLcqFKNwZnSi", "-KZawhnFZLcqFKNwZnSi", "-KZawhnFZLcqFKNwZnSi", "-KZawxBSAwL-lbi7dF-h", "-KZawxBSAwL-lbi7dF-h", "-KZawxBSAwL-lbi7dF-h", "-KZawxBSAwL-lbi7dF-h", "-KZawxBgz8k7v8-fKpDV", "-KZawxBgz8k7v8-fKpDV", "-KZawxBgz8k7v8-fKpDV", "-KZawxBgz8k7v8-fKpDV" ]
}
}
What you're trying to model is a set: a collection of unique entries.
What you've modeled is an array: a sequence of non-unique entries.
The simplest and best solution is to change your data model to actually reflect a set. The closest you can get to that in Firebase is:
"sList" : {
"-KZawgegLrIyq9h6GSf8" : {
"name" : "Test",
"users" : {
"-KZawhnFZLcqFKNwZnSi": true,
"-KZawxBSAwL-lbi7dF-h": true,
"-KZawxBgz8k7v8-fKpDV": true
}
}
}
With such a set-like structure, duplicates are automatically prevented by the data structure itself. You won't need to write security rules for that.

How to structure data in Firebase created by one user but accessible to users in a group?

So, let's say I have data like this:
{
"events" : {
"s0d980983s" :
{ creator: "bob#bob.com",
text: "Bob says 'My name is Robert'" },
"kjl34jl234j" :
{ creator: "fred#fred.com",
text: "Fred says 'My name is Fredrick'" }
}
"users" : {
"bob#bob.com" : { "paid": true },
"fred#fred.com" : { "paid": false }
}
}
I'm assuming this is the correct way to structure the data. When the data is created, I use the push() method to create a new key for the data, and then store the creator of the data inside it.
I'd like to make it so that:
I can allow anyone from a group of users to access certain data (and disallow others obviously).
The query is "optimized," meaning if I have thousands of records I am not iterating over all the data.
More concretely, for example, I want lizzie#lizzie.com to be able to see the s0d980983s.
I'm confused how to structure the data, and what my Firebase rules should look like.
Would it be something like this?
{ "events" : {
"s0d980983s" :
{ creator: "bob#bob.com",
viewers: { "bob#bob.com": true,
"lizzie#lizzie.com" : true },
text: "Bob says 'My name is Robert'" },
...
}
I don't understand how I can search for events that are viewable by a group of users. I don't believe Firebase supports some kind of wildcard that would make this code work, right?
var ref = firebase.database().ref( "events/*/viewers/lizzie#lizzie.com" ).on(...);
Do I also want to reference the events inside my users table? I'm not sure I understand how to flatten data (denormalize it) and keep references in both places to support a query like this. Should I expect to make multiple queries where I first retrieve a list of events stored in a user object and then retrieve them one by one using their key? But, how do I put that logic into my firebase rules?
{ "events" : {
"s0d980983s" :
{ creator: "bob#bob.com",
viewers: { "[insert bobs id]": true,
"[insert liz id]" : true
},
text: "Bob says 'My name is Robert'" },
...
}
Based on the above structure as you suggested, and if you are using firebase authentication to authenticate your user, you can add another 'read' or 'write' rule for checking whether that user is in the list of your 'viewers'. something like:
{
"rules": {
"users": {
"$uid": {
".write": "auth != null &&
root.child('users').child(auth.uid).child('viewers').child(auth.uid).val() ==
true"
}
}
}
}
This should help. setting firebase security rules at a location/node

how to retrieve data ordered by key inside unspecified key with firebase

I have a snapshot for my reference in firebase like this:
"friendlist" : {
"user1" : {
"user3" : 1
},
"user2" : {
"user1" : 0
}
"user3" : {
"user1" : 1
}
}
The explanation for the reference:
Every user has an unique id, i'm using user's id for their friendlist unique id. In example above i have 3 users and every user have his own friendlist. Inside their friendlist, there's other user's id that already be friend with him. If the value is 1, the user already be friend. But when the value is 0, the user is requesting to be friend.
My problem is:
How to get all user's friendlist's id which have "user1" with value 0 inside their friendlist? Can i do that in just one query?
I think i need to iterate through all friendlist and orderbykey for every friendlist and looking for "user1". Or there's any good approach to do that?
Any answer would be appreciated, thanks!
It would help if you next time tell a bit more about what you've already tried. Or at the very least specify what language/environment you're targeting.
But in JavaScript, you can get those users with:
var ref = new Firebase('https://yours.firebaseio.com/friendlist');
var query = ref.orderByChild('user1').equalTo(0);
query.once('value', function(usersSnapshot) {
usersSnapshot.forEach(function(userSnapshot) {
console.log(userSnapshot.key());
});
});
With the sample data you specified, this will print:
user2
You should add (and will get a warning about) an index for efficiently performing this query:
{
"rules": {
"friendlist": {
".indexOn": ['user1']
}
}
}
Without this index, the Firebase client will just download all data to the client and do the filtering client-side. With the index, the query will be performed server-side.
A better data model
You'll likely want to search for any friend, which turns the index into:
".indexOn": ['user1', 'user2', 'user3']
But with this structure, you'll need to add an index whenever you add a user. Firebase SDKs don't have an API to add indexes, which is typically a good indication that your data structure is not fitting your needs.
When using a NoSQL database, your data structure should meet the needs of the application you're building. Since you are looking to query the friends of user1, you should store the data in that format too:
"friendlist" : {
"user1" : {
"user3" : 1
},
"user2" : {
"user1" : 0
}
"user3" : {
"user1" : 1
}
},
"friendsOf": {
"user1": {
"user2": 0,
"user3": 1
},
"user3": {
"user1": 1
}
}
As you can see, we now store two lists:
* friendList is your original list
* friendsOf is the inverse of your original list
When you need to know who friended user 1, you can now read that data with:
ref.child('friendsOf').child('user1').on('value'...
Note that we no longer need a query for this, which makes the operation a lot more scalable on the database side.
Atomic updates
With this new data model, you need to write data in two places when adding a friend relation. You can do this with two set()/update() operations. But in recent Firebase SDKs, you can also perform both writes in a single update like this:
function setRelationship(user1, user2, value) {
var updates = {};
updates['friendList/'+user1+'/'+user2] = value;
updates['friendsOf/'+user2+'/'+user1] = value;
ref.update(updates);
}
setRelationship('user3', 'user4', 1);
The above will send a single command to the Firebase server to write the relationship to both friendList and friendsOf nodes.

Query firebase objects by user

I have a data structure that looks like:
{
"farms" : {
"-J3saHfe8_2GRqn3jOTc" : {
"stockunits" : {
"-J4CAeRI-IKKXVuNILCv" : {
"name" : "Chickens",
"totalStockUnits" : 115
}
},
"owner" : 3,
"name" : "smith"
},
"-J3sbbqsGabs5cLaj0zP" : {
"owner" : 2,
"name" : "brown"
}
}
}
When I query "/farms" I would like to get a list of the farms for which the authenticated user is the owner. I would also like to prevent users from viewing farms that they are not the owner for.
My rules currently look like this:
{
"rules": {
".write": false,
".read": false,
"farms": {
"$farm": {
".read": "data.child('owner').val() == auth.id"
I get that by putting the .read at this level I am granting read access to individual farm when accessed via /farms/:farmid. And if I move the ".read" up to the "farms" level this results in granting read access to the entire list.
So I think I need to restructure my data but aren't sure how best to go about this? I don't want to add the farms object below the user object as I will be wanting to add a number of "editor" users to any given farm as well.
Thanks for your help
You'll need to denormalize your data and include references to individual farm objects under each user's profile. There's a full example of how to do this kind of denormalization in this blog post: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html
In that example, the code snippets show organizing comments under posts, you can use a similar technique to map farms to users.

Resources