Firebase Query Help - Double Nested - firebase

I'm attempting to query some data put can't seem to get the call just right.
Here is an example piece of the data:
{
"currentSelectedPlayers" : {
"player1" : {
"assists" : "97",
"currentlyPickedBy" : {
"userID" : "641aada9-2d42-4b83-9883-ca316c842a08"
},
"goals" : "2",
}
}
In my rules I have set:
"rules": {
"$currentSelectedPlayers": {
".indexOn": ["currentlyPickedBy", ".value"]
}
}
My query: https://{database-address}.firebaseio.com/currentSelectedPlayers.json?orderBy="$value"&equalTo="641aada9-2d42-4b83-9883-ca316c842a08"&print=pretty
I know firebase recently introduced querying for deep nested data. How would I properly query for this nested data?

You don't need a .value index, but an index on the path ``:
{
"currentSelectedPlayers": {
".indexOn": ["currentlyPickedBy/userID"]
}
}
You can then query it with:
currentSelectedPlayers.json?orderBy="currentlyPickedBy/userID"&equalTo="641aada9-2d42-4b83-9883-ca316c842a08"&print=pretty
Give it a spin here:
https://stackoverflow.firebaseio.com/34644066/currentSelectedPlayers.json?orderBy=%22currentlyPickedBy/userID%22&equalTo=%22641aada9-2d42-4b83-9883-ca316c842a08%22&print=pretty

Related

indexOn not working on nested data

I currently have a data structure that looks like this
Rooms
-k-abcw2222
Messages
-k-112w12123 : {
text : 'hello'
msgdate : 1487558835433
}
-k-112w12125 : {
text : 'hello2'
msgdate : 1487558835633
}
I want to listen to every new message published to a room and am doing a
firebase
.database()
.ref('/Rooms/' + roomkey + '/Messages/')
.orderByChild('msgdate')
.on(...)
but I get the exception
No index defined for orderBy
I created the index as follows
{
"rules" : {
"Rooms" : {
"$Roomsid" : {
"Messages" : {
".indexOn": ["msgdate"]
}
...
}
and also tried creating the index as follows
{
"rules" : {
"Rooms" : {
"$Roomsid" : {
"Messages" : {
"$MessageId" : {
".indexOn": ["msgdate"]
}
...
}
but still did not work. Any suggestions?

firebase web - update database where a certain value is found

My database looks as below :
I need to update the division_name where the index_num is 3.
I tried the following code but it did not work -
var division_index_found="3";
var division_name_given="new div";
var query_update=firebase.database().ref("/divisions")
.orderByChild('index_num').equalTo(division_index_found);
query_update.once("child_added", function(snapshot) {
snapshot.ref.update({ division_name: division_name_given });
});
What approach to adopt here ?
EDIT1:
I get warning in chrome console :
FIREBASE WARNING: Using an unspecified index. Consider adding ".indexOn": "index_num" at /divisions to your security rules for better performance
EDIT2:
From the firebase database the districts node (?) looks like :
"districts" : {
"-KbVYCSO8wrMoXD3vL81" : {
"district_name" : "Rangpur",
"division_index" : "3",
"index_num" : 2
},
"-KbVYHgbWMDMtGsnmvei" : {
"district_name" : "jessore",
"division_index" : "3",
"index_num" : 3
},
"-KbVYKtSnPMFDkx9z0cU" : {
"district_name" : "district 1",
"division_index" : "3",
"index_num" : 4
}
}
Now I want to update district_name for a certain index_num and division_index. I use the following code :
var district_index="3";
var division_index="3"
var district_index_parsed = parseInt(district_index);
var query_update=firebase.database().ref("/districts")
.orderByChild('index_num').equalTo(district_index_parsed);
query_update.once("child_added", function(snapshot) {
snapshot.forEach(function(snapshot_indiv){
if(parseInt(snapshot_indiv.division_index)==parseInt(division_index)){
var district_name_again="new district name";
snapshot_indiv.ref.update({ district_name: district_name_again },function(error){
});
}// end of if division_index compare
});// end of forEach
});// end of query_update once
But the console shows :
Uncaught Error: No index defined for index_num
at je.get (firebase-database.js:94)
...
...
at edit_districts.php:359
...
which ultimately hints at the following line of code in my edit_districts.php file:
snapshot.forEach(function(snapshot_indiv){
inside the query_update.once part.The forEach method seems to make the problem.
And the security rules are defined as
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"divisions": {
".indexOn": "index_num"
},
"districts": {
".indexOn": "index_num"
},
}
}
How to get rid of the error to update the database ?
You'll need to add an index to your Firebase Database security rules. I recommend reading the Firebase documentation on security rules, specifically the section on indexes.
From the documentation comes this first sample:
{
"rules": {
"dinosaurs": {
".indexOn": ["height", "length"]
}
}
}
Modified to your data structure, it'll look something like this:
{
"rules": {
"divisions": {
".indexOn": "index_num"
}
}
}

Firebase Realtime Database - Rules - Does two objects have at least one common child?

I am trying to check, if two objects have at least one common child. In the following example I want to be able to be control, if people can read org.money.value.
The right to read is determined by comparing the children of org.keys and users.{auth.uid}.keys. If there is a common key, reading would be allowed.
Database JSON:
{
"org" : {
"keys" : {
"red" : {
"value" : "..."
},
"blue" : {
"value" : "..."
}
},
"money" : {
"value" : "..."
}
},
"users" : {
"John" : { // in reality John == auth.uid of a user
"keys" : {
"red" : {
"value" : "..."
}
}
},
"Alice" : { // in reality Alice == auth.uid of a user
"keys" : {
"green" : {
"value" : "..."
}
}
}
}
}
Rules:
"rules:"{
"org" : {
"money" : {
// can read if "org.keys" and "users.auth.uid.keys"
// have at least one common child name.
// With the above data reading would be allowed for John,
// but not for Alice.
".read" : what to write here?
}
}
}
Is it possible to make this work?
By the way, the organization does not know the auth.uid of users.
I can't think of any way that you could do this determination in the JSON rules with your current database structure. I would suggest altering your structure to allow for this type of read determination. Here's a potential solution I came up with, which will require more filtering on client side:
When you create a new user key, loop through the org keys to see if it is already contained there. If so, add a BOOL to the user object, perhaps "canReadMoney" and set it to true. Then, your rule for money would look something like this:
"rules:"{
"org" : {
"money" : {
".read" : "root.child('users').child(auth.uid).child('canReadMoney').val==true"
}
}
}
another solution could be storing endpoint in the database like this
usersShareOrg
{
"John": { "Org" : true }
"Alice": {"Org": false}
}
and these values would be calculated and stored every time you added new user or org.keys entity.

Firebase security rules for child items in arrays

I have the following data structure in my firebase:
{
"groups" : {
"-KEFQ7rTQscPX4hqn6ec" : {
"createdBy" : "b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c",
"description" : "Test",
"isPublic" : true,
"title" : "T1"
},
"-KEFQao_Wd-Y-nLzIx2e" : {
"createdBy" : "b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c",
"description" : "B",
"isPublic" : false,
"title" : "E"
}
}
and am trying to achieve the following:
Everybody can read all groups with "isPublic" == true
Only logged in users can see the groups that they have created
My first approach is:
{
"rules": {
"groups": {
".read": true,
"$id": {
".read": "data.child('isPublic').val() === true"
}
}
}
}
This stackoverflow post explains why it doesn't work, but I couldn't figure out how I can make it work.
Edit 1:
This post has a solution for the public/private problem (my 1. question) but not for the second question.
Edit 2:
Thanks to #VonD for the working solution for the public/private problem.
With this solution the problem with public/private is solved. Considering that a private group has many members and the user ids of them would be stored in another array "members" - how would I only allow access to the group if I am a member?
"privateGroups": {
"b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c": {
"-KEFQao_Wd-Y-nLzIx2e" : {
"createdBy" : "b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c",
"description" : "B",
"title" : "E",
"members": [userId1, userId2, userId3...]
}
}
}
The required security rules cannot be implemented with your document structure : if you want to express that a given user can read some of the child documents of a given node, the user will only be able to access them with their full path, for example "groups/-KEFQao_Wd-Y-nLzIx2e", but he will not be able to retrieve a list of groups matching the given criteria (unless of course you maintain at a different path a list of the groups the user can access, which means you would duplicate all public groups ids for each user).
A document structure that would better fit firebase security rules would be :
{
"publicGroups": {
"-KEFQ7rTQscPX4hqn6ec" : {
"createdBy" : "b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c",
"description" : "Test",
"title" : "T1"
}
},
"privateGroups": {
"b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c": {
"-KEFQao_Wd-Y-nLzIx2e" : {
"createdBy" : "b5cd3a86-108e-4ef3-9ab8-8a1e4da7491c",
"description" : "B",
"title" : "E"
}
}
}
}
Security rules would then be easy to implement:
{
"publicGroups": {
".read": true
},
"privateGroups": {
"$userId": {
".read": "auth.uid === $userId"
}
}
}
Hope it helps.

Firebase - Index rule for attributes under key created by ChildAutoById

I store my data on Firebase with the format
{
"list": [
"id created by Firebase": {
"foo": "bar"
},
"another id created by Firebase": {
"foo": "bar"
},
...
]
}
I would like to create an index on foo, using Firebase Rules.
However, according to Firebase doc, I need to know the specific ID created by Firebase to put in the rules specification.
Does anyone know of a way to get around this?
You don't need to know the specific ID, that wouldn't be possible. You simply need to have an .indexOn rule on the parent node. https://www.firebase.com/docs/security/guide/indexing-data.html
{
"rules": {
"list": {
".indexOn": ["foo"]
}
}
}
If you need to add additional rules for the children, then you add those normally like so:
{
"rules": {
"list": {
".indexOn": ["foo"],
"$item": {
"foo": {
".validate": "newData.isString()"
}
}
}
}
}

Resources