firebase - get all chat rooms for a member - ios

I'm integrating multi-room chat in my app and I'm stuck with getting a list of all chat room a specific user is member of.
The structure looks like this:
The rooms and members are created with childByAutoId like this:
FIRUser *user = [FIRAuth auth].currentUser;
mdata[#"uid"] = user.uid;
roomKey = [[_rootRef child:#"messages"] childByAutoId].key;
NSString *memberID = [[[_rootRef child:#"members"] child: roomKey ] child: user.uid ].key;
// set Meta data for member to be able to recognize later
[[[[_rootRef child:#"members"] child: roomKey ] child: memberID ] setValue:mdata];
Now I'm trying the get the list of rooms for a (hard coded) user like that:
-(void) getRoomKeys {
[[[[_rootRef child: #"members"] queryOrderedByChild:#"uid" ] queryEqualToValue:#"QLfRoGpoCjWpzira7fljBj8g3EJ3"]
observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSDictionary<NSString *, NSString *> *message = snapshot.value;
}];
}
This return 0 key/value pairs.
When I take out the query I get all room keys. When I change the structure to this
I will get all rooms for that user but with this structure I can't add other members to that room. So I need to dig one level deeper.
So how to set the query for nodes that have been created by childByAutoId?
Thanks for your help!

Try considering this data structure.
{
"rooms": {
"-KQgDxLIt88yPt6nacDu": { ... }
},
"members": {
"QLfRoGpoCjWpzira7fljBj8g3EJ3": { ... }
},
"member-rooms": {
"QLfRoGpoCjWpzira7fljBj8g3EJ3": {
"-KQgDxLIt88yPt6nacDu": true
}
}
}
You can retrieve the keys of the rooms a member is part of by observing member-rooms/{uid}:
[[_rootRef child: #"member-rooms/QLfRoGpoCjWpzira7fljBj8g3EJ3"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSLog("%#", snapshot.value); // the keys of the rooms of the member
}];

Related

Firebase snapShot value order changed after converting to NSDictionary

I am trying to get data from firebase database using firebase query
self.getReferencePath().child(User.followingReferencePath).queryOrderedByKey().queryLimited(toLast: 5)
When I pass this query to firebase and print the snapshot.value, I get the data in the order present in firebase as following
snapshot.value {
"-L2_hNtqB5UCBzgMFX0m" = {
"debate_id" = "-L2_hNtqB5UCBzgMFX0m";
};
"-L2_hSQSl7T5cDCfDoiV" = {
"debate_id" = "-L2_hSQSl7T5cDCfDoiV";
};
"-L2_h_vrwqID5Esl6gOk" = {
"debate_id" = "-L2_h_vrwqID5Esl6gOk";
};
"-L2_hfAruruMjzrLEZtI" = {
"debate_id" = "-L2_hfAruruMjzrLEZtI";
};
"-L2_hk2Uq7IBcflkO5YQ" = {
"debate_id" = "-L2_hk2Uq7IBcflkO5YQ";
};
}
But after converting the snapshot.all values as NSArray, the order changes as follow
let followingDbate = followingDebatesSnapshot.allValues as NSArray
print("followingDbate",followingDbate)
followingDbate (
{
"debate_id" = "-L2_hk2Uq7IBcflkO5YQ";
},
{
"debate_id" = "-L2_h_vrwqID5Esl6gOk";
},
{
"debate_id" = "-L2_hfAruruMjzrLEZtI";
},
{
"debate_id" = "-L2_hNtqB5UCBzgMFX0m";
},
{
"debate_id" = "-L2_hSQSl7T5cDCfDoiV";
}
)
I want to get the last Id as=nd pass it through another query. As the order changes I am not able to get the last id correctly. Please advice how to get the data without changing the order and also ow to get the last id from the snapshot I get. Thanks in advance

Retrieving data in firebase

I am a beginner in firebase and in iOS. I am trying to change a project from parse to firebase.I successfully created and updated the firebase database. But while trying to retrieve data from firebase its just not working for me.
Here's the code I used.
self.ref = [[FIRDatabase database] reference];
NSString *userID = [FIRAuth auth].currentUser.uid;
[[[ref child:#"users"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSLog(#"%#",snapshot.value);
// Get user value
}withCancelBlock:^(NSError * _Nonnull error) {
NSLog(#"%#", error.localizedDescription);
}];
The control just skips the whole block. I can't figure out the problem.
The firebase guide is very hard to understand. Please tell me how to get values to a dictionary from a firebase child.
DatabaseReference database =
FirebaseDatabase.getInstance().getReference();
database.child("notes").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List notes = new ArrayList<>();
for (DataSnapshot noteDataSnapshot : dataSnapshot.getChildren()) {
Note note = noteDataSnapshot.getValue(Note.class);
notes.add(note);
}
adapter.updateList(notes);
}
...
});

Firebase - don't get message with read rules

I'm trying to set up a chat room in IOS with firebase. Things work fine when I test in the simulator of the firebase console but do not work in IOS app.
The structure I use is like this
root/members/room-id/auth.uid/userdata
root/messages/room_id/messages/message
I create a new room in IOS with
- (void)initRoom
{
NSMutableDictionary *mdata = [[NSMutableDictionary alloc] init];
FIRUser *user = [FIRAuth auth].currentUser;
mdata[#"uid"] = user.uid;
// get the key for the new room
roomKey = [[_rootRef child:#"messages"] childByAutoId].key;
if (roomKey != nil) {
// add auth.uid to member/roomkey
NSString *memberID = [[[_rootRef child:#"members"] child: roomKey ] child: user.uid ].key;
[[[[_rootRef child:#"members"] child: roomKey ] child: memberID ] setValue:mdata];
[self addMemberToRoom];
}
}
and add the other member for that room (using hard coded uid, for now):
-(void) addMemberToRoom{
NSString *memberID = [[[_rootRef child:#"members"] child: roomKey ] child: #"QLfRoGpoCjWpzira7fljBj8g3EJ3"].key;
NSMutableDictionary *mdata = [[NSMutableDictionary alloc] init];
mdata[#"uid"] = #"QLfRoGpoCjWpzira7fljBj8g3EJ3";
if (memberID !=nil) {
[[[[_rootRef child:#"members"] child: roomKey ] child: memberID ] setValue:mdata];
}
// start listener
[self observeMessages];
}
The console show this for members:
and this for messages:
and start the listener like this:
-(void)observeMessages
{
_msgHandle = [[[_rootRef child:#"messages"] child: roomKey] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
NSDictionary<NSString *, NSString *> *message = snapshot.value;
NSString *name = message[#"senderId"];
NSString *text = message[#"message"];
[self addMessagewithId:name andText:text];
// animates the receiving of a new message on the view
[self finishReceivingMessage];
}];
}
This is all working well to add a message to the database and see it in the app when I set rules like this:
{
"rules": {
"members": {
".read": "auth !== null",
".write": "auth !== null",
},
"messages": {
".write":"auth !== null",
".read": "auth !== null",
"$room_id": {
}
}
}
}
Now, since I don't want everybody being able to read the messages I set the rule to:
{
"rules": {
"members": {
".read": "auth !== null",
".write": "auth !== null",
},
"messages": {
".write": "auth !== null",
"$room_id": {
".read": "root.child('members/'+$room_id+'/'+auth.uid).exists()",
}
}
}
}
When I do this, the listener in the IOS app will not receive any call. Checking for the room_id and user created from the app with the simulator in the firebase console the read is flagged OK.
My assumption was, that the listener was initialized before the new members where created but even delaying the initializing did not help.
Could you help me by pointing me to the right direction? Thanks a lot!
OK, I found a solution that works for now. The observer for the chatroom was created before the chatroom is available in the members list, thus the .read rule returns false.
My workaround is setting an observer to the members list that starts the observer for messages when it fires.
This is my code:
-(void) getLastRoom // invoked when new room is added to members node
{
FIRUser *user = [FIRAuth auth].currentUser;
NSString *uid = user.uid;
_msgHandle = [[[[_rootRef child:#"members"] child: roomKey] queryEqualToValue: uid] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSString *chatRoom = snapshot.key; //-> returns the roomkey of the chatroom
if ([chatRoom isEqualToString:roomKey]){
[self observeMessages];
}
}];
}
Hope it might help somebody.

NSArray with nested objects "losing" objects in memory

So in a block I am getting and parsing a JSON object that looks like this (any time you see "<...>" assume properly formed data)(also this is only one of the objects in question):
{
asset = {
<...>
};
<...>
sections = (
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
{
<...>
properties = {
title = "We welcome guests...";
};
},
{
<...>
properties = {
title = "More text";
};
},
{
<...>
properties = {
title = "Opportunity Insert...";
};
}
);
},
{
<...>
fields = (
{
<...>
values = (
Private,
Public
);
},
{
<...>
values = (
);
},
{
<...>
values = (
);
}
);
items = (
);
},
{
<...>
fields = (
{
<...>
values = (
);
},
{
<...>
values = (
);
}
);
items = (
);
}
);
}
The code to get this(using AFNetworking):
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:AppsURL([[NSUserDefaults standardUserDefaults] objectForKey:kAuthToken])]];
AFHTTPRequestOperation* op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
[op setResponseSerializer:[[AFJSONResponseSerializer alloc] init]];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject != nil&&[responseObject isKindOfClass:[NSDictionary class]]) {
NSDictionary* dict = (NSDictionary*)responseObject;
if (dict[#"apps"]&&[dict[#"apps"] isKindOfClass:[NSArray class]]) {
apps = dict[#"apps"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
return;
}
}
NSLog(#"Error Loading apps:%#",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error:%#",error);
NSLog(#"Response:%#",operation.response.description);
}];
[op start];
At this point everything is loading into memory and working perfectly. I set this to a class-level NSArray and then use that NSArray to fill a table. The problem comes when I try to retrieve the data after the user picks one of the items from the table. I then use the index and pull that object from the NSArray to find that is looks like this(note the fact that all item and field arrays are now empty):
{
asset = {
<...>
};
<...>
sections = (
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
}
);
}
Code for select:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row < apps.count) {
//the output of this is what I copy and pasted
NSLog(#"app data to be cleaned up:%# \r app data sent:%#",apps[indexPath.row],((NSDictionary*)apps[indexPath.row]).mutableCopy);
//I originally thought the problem was here, but the output above proved me wrong
NSMutableDictionary *app = [Functions recurseDictionaryForNull:((NSDictionary*)apps[indexPath.row]).mutableCopy];
[[NSUserDefaults standardUserDefaults] setObject:app
forKey:#"app"];
MainMenuViewController* mainMenu = (MainMenuViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"mainMenu"];
[self.navigationController setViewControllers:#[mainMenu] animated:YES];// reset nav stack
}
}
I'm kinda at a lose... any ideas what could be doing this and how to fix it??
It was the data from the server. I was told 2 "apps" were the same except for one item and turns out they were missing all of the fields and items as well. Thanks Dima and Mike for taking the time anyways!

iOS5 - How to parse JSON response from Facebook [duplicate]

I am using Facebook Graph API...for fetching the data of news feed of the facebook profile..
and here is the response that i am getting in the console
{
application = {
id = 2309869772;
name = Links;
};
"created_time" = "2011-02-10T09:44:27+0000";
from = {
id = 1845195019;
name = "Paritosh Raval";
};
icon = "http://static.ak.fbcdn.net/rsrc.php/v1/yD/r/aS8ecmYRys0.gif";
id = "1845195019_192144087475935";
likes = {
count = 1;
data = (
{
id = 1845195019;
name = "Paritosh Raval";
}
);
};
link = "http://www.facebook.com/AMDAVAD";
name = "once you live in AHMEDABAD u cannot live anywhere else in the world..";
picture = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/203562_115963658443669_4129246_n.jpg";
properties = (
{
name = Page;
text = "21,803 people like this.";
}
);
type = link;
"updated_time" = "2011-02-10T09:44:27+0000";
},
{
application = {
id = 2392950137;
name = Video;
};
"created_time" = "2011-02-02T04:18:22+0000";
description = "must watch and explore :))";
from = {
id = 1845195019;
name = "Paritosh Raval";
};
icon = "http://static.ak.fbcdn.net/rsrc.php/v1/yD/r/aS8ecmYRys0.gif";
id = "1845195019_194836027209359";
likes = {
count = 1;
data = (
{
id = 100000701228096;
name = "Bhargav Jani";
}
);
};
link = "http://www.facebook.com/video/video.php?v=152586058110610&comments";
name = "It Happens Only in....";
"object_id" = 152586058110610;
picture = "http://vthumb.ak.fbcdn.net/hvthumb-ak-snc4/50893_152586468110569_152586058110610_18299_1832_t.jpg";
properties = (
{
name = Length;
text = "0:54";
}
);
source = "http://video.ak.fbcdn.net/cfs-ak-ash2/70137/56/152586058110610_53804.mp4?oh=481e53b824f6db8e3195fc9c0d07571d&oe=4DAFC300&__gda__=1303364352_7670272db65e93ec75dcaaed16b6d805";
type = video;
"updated_time" = "2011-02-02T04:18:22+0000";
}
And I want to show every data in the organized structure in the console. Can anyone help me with this?
it's unclear what you exactly asking but I try to answer.
First of all you need to parse this response in the method
- (void)request:(FBRequest *)request didLoad:(id)result of Facebook iOS SDK
result can be a string, a NSArray if you have multiple results and NSDictionary
In you console output we can see NSDictionary with included arrays and dictionaries in it.
I have little tutorial about it but it's on russian only and site is down today :( so i just copy one example from my article.
Let say we want to know what facebook user Likes
- (IBAction)getUserInfo:(id)sender {
[_facebook requestWithGraphPath:#"me/likes" andDelegate:self];
}
if we try this Graph API response in browser or output to console we can see what this request returns. It returns dictionary with one and only key - "data" and corresponded array to this key. This array contents dictionary objects again with keys -
«name»,"category","id","created_time". Dont forget request «user_likes» permission before.
So we have parsing method like that:
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]]) {
result = [result objectAtIndex:0];
}
if ([result objectForKey:#"owner"]) {
[self.label setText:#"Photo upload Success"];
} else if ([result objectForKey:#"data"]){
NSArray *likes = [result objectForKey:#"data"];
NSString *text=#"You don't like Steve";
for (NSDictionary* mylike in likes) {
NSString *mylikeName = [mylike objectForKey:#"name"];
if ([mylikeName isEqualToString:#"Steve Jobs"]) {
text=#"You like Steve";
break;
}
}
[self.label setText:text];
}
};
You can parse you result same way and fill your object's variables and then use it to display information in TableView for example. good luck!

Resources