I'm using Firebase with Polymer 2.0. My Firebase database contains users and groups. A user can be part of more than one group. A user can have different roles in different groups.
I want to list all groups where user is a member but I cant find a way to limit the firebase query to groups where user is a member. It's listing everything or nothing.
Database structure looks like this:
{
"groups" : {
"$groupId" : {
"members" : {
"$userId" : "true",
},
"name" : "Group Name A"
},
},
"users" : {
"$userId" : {
"groups" : {
"$groupId" : "true",
},
"settings" : {
"name" : "Linus"
}
}
}
}
Query looks like this:
<firebase-auth user="{{user}}"></firebase-auth>
<firebase-query
id="query"
path="/groups"
order-by-child="members/{{user.uid}}"
equal-to="{{user.uid}}"
data="{{accounts}}">
</firebase-query>
Expected result in this case would be to only display groups where $userId is true.
Related
I try to create a people of the world model in Firebase. This means that somewhere I need to put 500 miljon+ records like this Firebase json:
"USER" : {
"HnhLyXRxUINmlltKOfxx2QBYiQ53" : { // FireBase user ids
"FRIENDLYS" : {
"-KWrFrMx1yQe0jhyA7HP" : { // Push ids
"animal" : "dog"
},
"-KWrG7EsLkZvASjpcW3A" : {
"animal" : "cat"
},
"-KWrG9hbQxrZwdfjqbuQ" : {
"animal" : "horse"
}
},
"email" : "someemail#gmail.com",
"lastName" : "Doe",
"firstName" : "John",
"googleId" : "10086464927329323e2326"
},
"HnhLyXHKJH67677GJKMnbBYiQ53" : { // FireBase user ids
"FRIENDLYS" : {
"-KWrFrMdjnjs982s7HP" : { // Push ids
"animal" : "ant"
....
}
I want to search for one USER like this:
firebase.child("USER/HnhLyXRxUINmlltKOfxx2QBYiQ53").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The question is if this is a good approach to keep building on, especially Is it feasible to have a "USER" object this big when searching like i do?
What can I expect?
Your code is not searching for a user. You're constructing a direct reference to a child node, which operation itself does not have any performance implications. Looking up a key directly is always fast, so the number of users will not negatively affect your application.
However, storing "FRIENDLYS" [sic] under the user does not scale. Loading a single user node will get slower with each extra child put there. You should store them separately under a different root node and load them only if you actually need them.
See also the Structure Your Data section of the Realtime Database guide.
This is the database for example:
"Messages" : {
"Message1" : {
"Uid" : "sampleid1"
"Text" : "hi"
},
"Message2" : {
"Uid" : "sampleid2"
"Text" : " hello"
}
}
I want only those users to read the messages whose uid is equal to the Uid field of Message#.
The structure of database given in firebase documentation(i.e. using user id based messages in the database where the node of each message represents the uid of the user who sent the message) doesn't achieve the goal of my project as I need to know the uid of the user who sent the message each time any user sends a message.
Therefore, please suggest the rules that would help me achieve my task as mentioned in this question
Also, when I applied certain rules on the above structure of database, I couldn't read any data because 'firebase rules are not filters'.
Please ignore the syntax and format of json written in above example as it is just for reference
Please help!
Structure your data so:
"messages" : {
"<receiver_uid>" : {
"msg_1" : {
"text" : "Hello world...",
"uid" : "<sender_uid>"
}
// more msgs for this receiver ...
}
}
the rules should be something like
{
"rules" : {
"messages" : {
"$receiver" : {
".read" : "auth.uid == $receiver", // only receiver shall read
".write" : "auth != false" // any authenticated user can write
}
}
}
}
I have a Firebase data structure that looks like:
-messages
-myFirstUsername
-5-2-16 04:02:23 AM
-message: 'messageOne',
-direction: 'outgoing'
-5-3-16 04:07:23 AM
-message: 'messageTwo',
-direction: 'outgoing'
-mySecondUsername
-5-4-16 04:02:23 AM
-message: 'messageOne',
-direction: 'outgoing'
-5-5-16 04:02:23 AM
-message: 'messageTwo',
-direction: 'incoming'
I would like to index all data using the message and direction nested child keys. Since the username keys under the messages object are dynamic, I'll need to set up my index on the messages object itself.
Will the following rule set up indices two levels deep?
{
"rules": {
"messages": {
".indexOn": ["message", "direction"]
}
}
}
You can specify dynamic .indexOn like this:
{
"rules" : {
"messages" : {
"$userId": {
".indexOn" : ["message", "direction"]
}
}
}
}
I can't seem to find it in the new docs, but here's the old docs description: https://www.firebase.com/docs/security/api/rule/path.html
I've got a question on how to combine data from different Firebase database nodes before displaying it on the frontend. I've got a Firebase database with the following structure. (I'm new to a nosql setup, so this looks more relational):
{
"agents" : {
"-KPCmnwzjd8CeSdrU3As" : {
"contactNumber" : "12345",
"name" : "aaa"
},
"-KPCmw6dKuopDlsMVOlU" : {
"contactNumber" : "123",
"name" : "bbb"
},
"-KPCoWcLecpchcFV-vh_" : {
"contactNumber" : "123",
"name" : "ccc"
},
"-KPROMhPatLjVxMdvfLf" : {
"contactNumber" : "256342",
"name" : "blah"
},
"-KPWIFl5qp5FvAeC3YhG" : {
"contactNumber" : "123",
"name" : "eee"
}
},
"listings" : {
"-KPWKTvW3GzFEIT2hUNU" : {
"agent" : "-KPCoWcLecpchcFV-vh_",
"description" : "third",
"reference" : "REF1"
}
}
}
I'm using Firebase SDK 3.2.0 and AngularFire 2.0.1. In my Angular app I am able to get the list of listings, and for each one look up the agent information. The reason I'm not storing the agent info with the listing is I want the ability to update the agent and the change should reflect on all listings. I don't want to have to go and update all listings if the agent telephone number changes (as an example).
In my controller I have the following:
// get the listings
var listingsRef = firebase.database().ref().child('listings');
vm.listings = $firebaseArray(listingsRef);
// this will move to my ui-router as a resolve but for simplicity's sake
// I added it here...
vm.listings.$loaded().then(function(data){
// loop through the listings...
data.forEach(function(listing) {
if (listing.agent) {
// get the agent for the listing
listing.agent = AgentFactory.getAgent(listing.agent);
}
});
});
Right now the data is displaying correctly on the frontend. There is a slight delay with the agent data showing because of the need of the getAgent promise to resolve.
My questions are:
Is this the correct way of getting the agent data? Should I be looping through the listings and for each query the agent data? How do I wait / keep track of all of the getAgents to resolve?
Any help would be appreciated.
Thanks.
I've structured my data similarly. If you want to wait for all the getAgents to resolve you can use $q.all. I'm not entirely sure what your AgentFactory.getAgent is returning, but let's assume it's a $firebaseObject. If that's the case inject $q and then do the following:
vm.listings.$loaded().then(function (data) {
// loop through the listings...
var promises = [];
data.forEach(function (listing) {
if (listing.agent) {
// get the agent for the listing
listing.agent = AgentFactory.getAgent(listing.agent);
promises.push(listing.agent.$loaded());
}
});
return $q.all(promises);
}).then(function (agents) {
//all agents are loaded
});
This question already has answers here:
Restricting child/field access with security rules
(3 answers)
Closed 6 years ago.
I'm using the Objective-C API for Firebase to fetch data and am able to do so when my security rules (set via the Firebase online dashboard) don't utilize any wildcard paths, e.g.:
{
"rules": {
"user" : {
".read" : true,
".write" : true
},
"users" : {
".read" : true,
".write" : false
}
}
}
But when I try enact what should be identical security rules using wildcard paths and fetch objects, the completion handler never executes, e.g.:
{
"rules": {
"user" : {
".read" : true,
".write" : true
},
"users" : {
"$userId" : {
".read" : true,
".write" : false
}
}
}
}
I used the Firebase documentation at the following URL and can't figure out what I'm doing wrong: https://www.firebase.com/docs/security/quickstart.html
I don't think the problem is Objective-C specific, but just to be thorough I'm using the method -[FQuery observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) { }] to fetch my data.
Update: Here's the output of po query for the particularly FQuery I'm using to debug:
(/users {
ep = 0;
i = hidden;
sp = 0;
})
Update 2: Here's my data structure, in case that is relevant:
{
"user" : {
"HhMeloQDY4" : {
"info" : {
"name" : "Anita Borg"
}
},
"QxnjCNOj3H" : {
"info" : {
"name" : "Charles Babbage"
}
},
"zeNalC4ktf" : {
"info" : {
"name" : "Beyoncé"
}
}
},
"users" : {
"HhMeloQDY4" : {
"hidden" : false
},
"QxnjCNOj3H" : {
"hidden" : false
},
"zeNalC4ktf" : {
"hidden" : true
}
}
}
Update 3: Here's my Objective-C code for how I create my FQuery object:
Firebase *firebase = [[Firebase alloc] initWithUrl:#"https://<my-app-name>.firebaseio.com"];
[[firebase childByAppendingPath:#".info/connected"] observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
BOOL isConnected = [snapshot.value boolValue];
// broadcast whether app is connected to Firebase
}];
Firebase *directory = [firebase childByAppendingPath:#"users"];
FQuery *query = [directory queryOrderedByChild:#"hidden"];
query = [query queryEqualToValue:value];
[query observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
// data successfully retrieved from Firebase
}];
You have added read access at the path /users/specific_user_id/ but you're attempting to read at the path /users/, which has no read access allowed.
You'll need to provide access to the path you are attempting to read, not just a subset of its children. See security rules are not filters.
Edit: Just adding some ObjC code to clarify
With the query presented
Firebase *directory = [self.myRootRef childByAppendingPath:#"users"];
you are querying the nodes directly inside the users node. However, if you review the structure, what's inside the users node is not queryable as there are no rules directly under /users, where I have commented.
"users" : {
//OH NOES! There are no rules here!
"$userId" : {
".read" : true,
".write" : false
}
Your rules are inside the $userId, which represents and applies to that parent only
"$userId" : {
//these rules *only* apply inside each userId.
".read" : true,
".write" : false
}
So with your structure, this query would work and it would query the content inside users/HhMeloQDY4 only.
Firebase *directory = [self.myRootRef childByAppendingPath:#"users/HhMeloQDY4"];
So the end result is that you need to assign the rules directly under the /users node that will allow you to query for content within it's child nodes.
"users" : {
".read" : true,
".write" : false
"$userId" : {
}
This would allow you to read each node under users node ($userId and it's children) but not write to them.