Firebase REST API query with different keys - firebase

So this is the structure of my Firebase DB right now, I am using the Firebase REST API:
"company": {
company1_id {
id: company_id,
userId: userid,
name: name
//someotherstuff
}
company2_id {
id: company_id,
userId: userid,
name: name,
//someotherstuff
}
}
Soo, right now I am getting the companies belonging to one user by calling :
"firebasedbname.firebaseio.com/company.json?orderBy="userId"&equalTo=userId"
This works perfectly fine and gets the corresponding data, but now I want it to order the companies alphabetically by name, and then i try this:
"firebasedbname.firebaseio.com/company.json?orderBy="name"&equalTo=userId"
But this time, it returns no data! Even though i have added .indexOn: "name" to the company node.Any help will be aprreciated.

As explained in the doc, if you want to filter data you need to first "specify how you want your data to be filtered using the orderBy parameter", and then you need to "combine orderBy with any of the other five parameters: limitToFirst, limitToLast, startAt, endAt, and equalTo".
So if you added "an .indexOn: "name" to the company node", it means that you intend to query as follows:
https://xxxx.firebaseio.com/company.json?orderBy="name"&equalTo="companyName"
You cannot order by (company) name and filter on userId.
If you want to get all the companies corresponding to a specific user and order them by the company name, you will need to use ?orderBy="userId"&equalTo=userId" and do the sorting in the client/application calling the REST API.

Related

Hasura object permission based authorization

I am trying to set a "Row Select" permissions on Hasura. I have a (simplified for brevity) Data Model like below
User
id: UserID
App
id: AppID
App Permissions
user_id: User ID
app_id: App ID
permissions: [ ENUM: Admin, View, Owner ]
Feed
app_id: AppID
feed_data: Some Feed Data
Now, I wish to query all Feed for an authenticated user. The query can be of the form
GET all apps, for which the authenticated user has view permissions
query MyQuery {
feed(limit: 10) {
app_id
feed_data
}
}
GET apps with app_id in the query filter for which the authenticated user has view permissions
query MyQuery {
feed(limit: 10, where: {app_id: {_in: [1, 2]}}) {
app_id
feed_data
}
}
Since feed table does not have user_id information directly in it, I can not use X-Hasura-User-Id attribute directly against feed table. I also tried to use _exists relation against the app_permission table, but I am unable to put app_id filter in the permission clause.
{
"_exists": {
"_where": {
"user_id": {
"_eq": "X-Hasura-User-Id"
}
},
"_table": {
"schema": "public",
"name": "app_permission"
}
}
}
I am not really sure how to proceed with such data modelling with Hasura. Any help is appreciated. Thanks.
Since you dont have a direct relationship, I think you can query via appPermissions Table instead of directly querying feeds table.
When you create a feeds table with appId as foreign key relationship, Hasura lets you track this relationship as shown below
This way you can make nested graphQL queries to appPerms table as shown below
query GetUserFeeds {
test_appPerms {
id
userId
feeds(limit: 10) {
app_id
id
feed_data
}
}
}
Another thing I'd like to suggest is that you could try is by using a session variable like x-hasura-app-id along side a x-hasura-role and build your permissions around that.
https://hasura.io/docs/latest/graphql/core/auth/authorization/roles-variables.html

How to access an object into another object in a query database from firebase functions?

I am trying to access to a object into another object in my firebase database, i have a structure like this:
I want to get all the objects that have the email that i send by parameters, i am using .child to access to the childs into my object but i am not success with the query, this is my code
$ ref_db.child("/groups").child("members").orderByChild("email").equalTo(email).once("value", (snapshot)=>{
console.log(snapshot.val());
});
The snapshot.val() always is undefined.
could you help me with the query?
One efficient way to get "all the groups that have that email inside the members object" would be to denormalize you data and have another "main node" in your database where you store all "members" (i.e. their email) and the "groups" they belong to.
This means that each time you add a "member" node under a "group" (including its email) you will also add the group as a child of the member email, in this other "main node".
More concretely, here is how would be the database structure:
Your current structure:
- groups
- -LB9o....
...
- members
- -LB9qbd....
-email: xxxx#zzz.com
- -LBA7R....
-email: yyyyy#aaaa.com
And the extra structure:
- groupsByMembers
- xxxxxx#zzzcom
- Grupo1: true
- yyyyy#aaaacom
- Grupo1: true
- Grupo2: true
- bbbcccc#dddcom
- Grupo6: true
- Grupo8: true
Note that in the "extra structure" the dots within an email address are removed, since you cannot include a point in a node id. You will have to remove them accordingly when writing and querying.
This way you can easily query for the list of groups a member is belonging to, as shown below. Without the need to loop several times over several items. This dernomalization technique is quite classic in NoSQL databases.
const mailToSearchFor = xxxx.xx#zzz.com;
const ref = database.ref('/groupsByMembers/' + mailToSearchFor.replace(/\./g, ''));
ref.once('value', snapshot => {
const val = snapshot.val();
for (let key in val) {
if (val.hasOwnProperty(key)) {
console.log(key);
}
}
});
In order to write to the two database nodes simultaneously, use the update method as explained here https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields
This is because you have a random key before members, you need to go through the path and not skip a node, to be able to access the values:
ref_db.child("groups").child("-LB9oWcnE0wXx8PbH4D").child("members").orderByChild("email").equalTo(email).once("value", (snapshot)=>{
console.log(snapshot.val());
});

Grabbing Keys with Firebase

I'm currently creating an app using ionic2 and firebase for a class and I've run into an issue.
I"m not posting code because I don't have anything relevant enough to the question.
In my database I have a 'group' that people can create. I need the 'group' to be able to store a list of users. The way I'm currently doing it is that users will click an addGroup button, and the currentUser will be added to the list of users in that group simply by typing in the name of the group. (yeah i know that's going to need a password or something similar later, people obviously shouldn't just be able to join by group name)
*Names of groups will all be different so I should be able to query the database with that and get a single reference point.
The problem is that I don't know how to properly query the database and get the key value of the group object I want.
I keep looking things up and cant find a simple way to get the key of an object. I feel like this is a dumb question but, I'm unfamiliar with typescript, firebase, and ionic2 so I'm pretty lost in everything.
Answer for the question in comment.
you can query the database like this
this.group_val:any="group1"
let group=db.list('/groups', {
query: {
orderByChild: GroupName, //here specify the name of field in groups
equalTo: this.group_val //here specify the value u want to search
}
});
group.subscribe(grp=> {
//you can use the grup object here
})
First, define your database structure. The below is probably best:
groups
<first group> (Firebase-generated ID)
name: "Cat lovers"
users:
user1ID: true
user2ID: true
<second group>
...
I assume that when the user clicks on the group he wants to join, you know the group ID. For instance, it could be the value of an option in a select.
Get the list of groups:
groups$ = this.angularFireDatabase.list('groups');
To populate a list of groups into a select:
<select>
<option *ngFor="let group of groups$ | async" [value]="group.$key">
{{group.name}}
</option>
</select>
To create a new group:
groups$.push({name: "Dog lovers"})
The select (drop-down) will update itself.
To add a user to a group:
addUserToGroup(groupId, userId) {
this.angularFireDatabase.list(`groups/${groupID}/users`).update(userID, true);
}
To find a group based on its name:
// Define the shape of a group for better type checking.
interface Group { name: string; users: {[userId: string]: boolean;}; }
// Keep local list of groups.
groups$: FirebaseListObservable<Group>;
groups: Group[];
// Keep an updated local copy of groups.
ngOnInit() {
this.angularFireDatabase.list('groups').subscribe(groups => this.groups = groups);
}
function findGroupByName(name) {
return this.groups.find(group => group.name === name);
}

Filter and sort on multiple values with Firebase

I'm building a social app using Firebase. I store posts in Firebase like this:
posts: {
"postid": {
author: "userid"
text: "",
date: "timestamp"
category: "categoryid"
likes: 23
}
}
Each post belong to a category and it's possible to like posts.
Now, I'm trying to show posts that belong to a specific category, sorted by the number of likes. It's possible I also want to limit the filter by date, to show only the most recent, most liked posts in a category. How can I do this?
Firebase query functionality doesn't seem to support multiple queries like this, which seems strange...
You can use only one ordering function with Firebase database queries, but proper data structure will allow you to query by multiple fields.
In your case you want to order by category. Rather than have category as a property, it can act as an index under posts:
posts: {
"categoryid": {
"postid": {
author: "userid"
text: "",
date: "timestamp",
category: "categoryid",
likes: 23
}
}
}
Now you can write a query to get all the posts underneath a specific category.
let postsRef = Firebase(url: "<my-firebase-app>/posts")
let categoryId = "my-category"
let categoryRef = postsRef.childByAppendingPath(categoryId)
let query = categoryRef.queryOrderedByChild("date")
query.observeEventType(.ChildAdded) { (snap: FDataSnapshot!) {
print(snap.value)
}
The code above creates a reference for posts by a specific category, and orders by the date. The multiple querying is possible by the data structure. The callback closure fires off for each individual item underneath the specified category.
If you want to query further, you'll have to do a client-side filtering of the data.

How can I achieve this Many-to-many relationship in Firebase?

I know Firebase does not support JOINs between nodes (like SQL Server does between tables), but that is exactly what I need to accomplish. Here's my situation:
I have a transactions node in Firebase like this (where I am including the category name for each transaction):
"transactions":
{
"-Jruazf35b9a_gAVmZBe":
{
payee: "McDonalds", amount: "2.35", category: "Eating Out"
}
"-JruadR11b4a_aTVmZFi":
{
payee: "Walmart", amount: "78.12", category: "Household"
}
"-Jruazf35b9a_AgvNWCq":
{
payee: "CapitalOne", amount: "150.00", category: "Debt"
}
"-JryJF2c33ijbjbBc24p":
{
payee: "FootLocker", amount: "107.54", category: "Personal Blow"
}
"-Jrz0T-aL61Vuw4SOqRb":
{
payee: "Starbucks", amount: "2.88", category: "Eating Out"
}
}
And I have a Categories node like this (where I am including the transactions under each category):
"categories":
{
"-Jruazf35b2a_gAVmZRy":
{
categoryname: "Eating Out",
categorytype: "Expense"
}
"transactions": {
"-Jruazf35b9a_AgvNWCq": {
payee: "McDonalds", amount: "2.35"
}
.
.
.
}
}
}
So far so good. My data is flat. I'm able to show the list of transactions with the category name (screenshot below) and I can show the list of transactions under each category in the expenses per category section (screenshot not shown here).
The problem I have is that if I rename a category the change is only reflected for future transactions. Past transactions show the old category name.
This is obvious due to the way I'm saving the data. So my first logical reaction was to save the category unique ID in the transactions node instead of the category name. However, that presents the challenge where, in my SQL Server little brain, I would need a JOIN so I can get the list of transactions and also include the name of the category for each transaction.
How can I structure my data so that I can:
show a list of transactions including the name of the category (as it does today)
allow a user to rename a category and show the change reflected for ALL transactions (past and future)
show a list of transactions under each category (I think the current approach would still be valid)
Joining data from two lists is inherently a slow operation, especially on NoSQL databases.
I would recommend keeping the categoryName and adding a categoryId. That way you can show your current screen with a single read, but also link to the category. For how to deal with updating the categoryName in each transaction, see How to write denormalized data in Firebase and https://medium.com/#collardeau/es6-promises-with-firebase-76606f36c80c.
Alternatively: the list of categories is likely to be relatively small. So you could also pre-load it and perform a client-side lookup while you're iterating the transactions.

Resources