Grabbing Keys with Firebase - 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);
}

Related

Firebase REST API query with different keys

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.

firebase what is the best way/structure to retrieve by unique child key

I have a firebase database like this structure:
-groups
--{group1id}
---groupname: 'group1'
---grouptype: 'sometype'
---groupmembers
----{uid1}:true
----{uid2}:true
--{group2id}
---groupname: 'group2'
---grouptype: 'someothertype'
---groupmembers
----{uid1}:true
----{uid3}:true
----{uid4}:true
Now, I am trying to pull groups of authenticated user. For example for uid1, it should return me group1id and group2id, and for example uid3 it should just return group2id.
I tried to do that with this code:
database().ref('groups/').orderByChild('groupMembers/' + auth().currentUser.uid).equalTo('true').on('value' , function(snapshot) {
console.log('GROUPS SNAPSHOT >> ' + JSON.stringify(snapshot))
})
but this returns null. if I remove "equalTo" and go it returns all childs under 'groups'.
Do you know any solution or better database structure suggestion for this situation ?
Your current structure makes it easy to retrieve the users for a group. It does not however make it easy to retrieve the groups for a user.
To also allow easy reading of the groups for a user, you'll want to add an additional data structure:
userGroups: {
uid1: {
group1id: true,
group2id: true
},
uid2: {
group1id: true,
group2id: true
},
uid3: {
group2id: true
},
uid3: {
group2id: true
}
}
Now of course you'll need to update both /userGroups and /groups when you add a user to (or remove them from) a group. This is quite common when modeling data in NoSQL databases: you may have to modify your data structure for the use-cases that your app supports.
Also see:
Firebase query if child of child contains a value
NoSQL data modeling
Many to Many relationship in Firebase

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());
});

Search by key, order by value

Here is a sample of my Firebase data:
I need to be able to search userFavorites for a given user (here, afaapy...) and return the results ordered by the values (timestamps) to get all the user's favorites in order of the date added to the database.
I can search by key as follows, and retrieve all favorites for the given user:
databaseRef.child("userFavorites").queryOrderedByKey().queryEqual(toValue: user.uid).observe(...)
But these favorties are ordered by their keys. If I try to order by value as follows, I get "Cannot use multiple queryOrderedBy calls!":
databaseRef.child("userFavorites").queryOrderedByKey().queryEqual(toValue: user.uid).queryOrderedByValue().observe(...)
How can I retrieve the favorites for a given user sorted by their value?
Second question: is there an easier way to retrieve data in the order it was added to the database?
You can't order the same ref multiple times as documented here
When you use a order or a filter method, it returns a Query Interface. See it as a filtered reference containing only a subset of the original data. It means that
databaseRef.child("userFavorites").orderByKey().equalTo(user.uid)
will not return userFavorite/${user.uid} but userFavorite filtered to show only the user.uid entry. You can see it by doing
databaseRef.child("userFavorites").orderByKey().equalTo(user.uid).ref.key
That should return 'userFavorites'
In your case, I see two options:
Keep going with orderByKey().equalTo() and sort the results yourself
Or use directly child() to get the user, then sort via Firebase (and don't forget to use the Firebase's snapshot.forEach to be sure you get the data in the query order):
databaseRef.child(`userFavorites/${user.uid}`).orderByValue().once('value', (snapshot) => {
if (snapshot.exists()) {
snapshot.forEach((child) => {
console.log(`${child.key}: ${child.val()}`)
})
}
})

Firestore data duplication

I'm trying to setup a friend system in Firestore. My data model looks like this at the moment:
collection("users") ->
document("user1")
document("user2")
...
A document in the users collection contains data like the name, email... of the user. I'd like to enable a user to have friends now, but I'm unsure about the best way to model this.
So, I'd for sure add a friends field in the documents of the users, but what should this field contain? My first thought was a pointer to a new collection called friends in which the documents are users. Something like this:
collection("users") {
document("user1") {
name:user1,
friends: -> collection("friends") {
document("user2"),
...
}
}
}
This seems reasonable, but that'd mean that I'd have a lot of duplicate data in my database because each user that has friends will be duplicated in a friends collection. Should I worry about this or is this normal in a Firestore database structure?
Would it perhaps be possible to point to a document in the users collection from the friends collection? Something like:
collection("users") {
document("user1") {
name:user1,
friends: -> collection("friends") {
document, -----
... |
} |
}, |
document("user2")<-
}
Or should I throw away the thought of using a collection for friends and just keep a list with uids of all friends of the user?
Seems you are using two separate collections for users and friends first all you can do it by one collection. But I don't want to go there may be there was another scenario.
As your separate collection way, you can design your friends collection model to meet no duplication:
{
name : 'Name',
email : 'email#mail.com'
has_connected : {
'user1' : true // here you can use anyother unique key from user
}
}
The thing is that firestore recommend this types of design for query and for faster performance you can make that has_connected key as index.
In this approach, you have to check during adding new friend by email or any other unique key. if exists then just put another key into has_connected with the respective user. e.g user2 : true.
Finally, for fetching all friends for a user you have to do a query like this: e.g: in javascript
let ref = firebase.firestore().collection("friends");
ref
.where(`has_connected.${username}`, "==", true)
.get()
.then(//do your logic)
.catch()
Thanks

Resources