Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Build a Self-Destructing Message iPhone App Retrieving and Viewing Data from Parse.com Retrieving Data from Parse.com

PFQuery Messages

Why do we query the backend where the "recipientIds" key is equal to the current user's objectId. Isn't the recipientIds an array? How could that possibly be equal to a single objectId?

Wouldn't a whereKey:contains: method be more applicable in this case?

Ben Jakuben

7 Answers

This says "query Parse and look for information with the class name "messages." PFQuery *query = [PFQuery queryWithClassName:@"Messages"];

This says take the query that we just performed and find the ones where the key named "recpientIds is the same as the current user's ID. [query whereKey: @"recipientIds" equalTo:[[PFUser currentUser] objectId]];

So it's a way of making sure that the user only sees messages that were directed toward them and not anybody else. I believe it looks inside of the array to see if there is any match and doesn't look at the array as a singular object, rather than an object that stores other objects.

I know what the query does, but the the value for the key @"recipientIds" is an array, as you can send messages to multiple people. Therefore, how can an array of recipient Ids equal one person's Id?

"I believe it looks inside of the array to see if there is any match and doesn't look at the array as a singular object, rather than an object that stores other objects." <-- That just isn't convincing enough for me. That's why I think a "contains" method would be better, but it seems to work for Ben Jakuben in the simulator.

I'm not sure what you're really asking. If it works the way it was written, then surely that's what it is doing. Otherwise there would be no way for the constraint to find the recipientIds because the key would just be equal to some array. If you look in the data browser on Parse it is written like this: ["SOU8JBvgFi","b0JFFyAc0l","FajWRNkChD","TKH49WuZru"] which leads me to believe that it is some sort of array of objectIds and the Parse backend system takes care of the job of looping through each value in the array in order to see if anything matches.

Maybe I'm wrong but I can't imagine any other way of Parse doing it?

I'm not a fan of assuming man. One thing about programming is that you can't assume or think anything is happening in the background. You must be 100% sure. I'd believe Parse documentation or a response from Ben Jakuben, but that's about it.

Well I'm okay with assuming at this point because the code works and it's not particularly necessary to know how. Otherwise you'd have to know how Parse handles every single aspect of their back end and that kind of defeats the purpose of having a third party back end to begin with.

Anyway, I did further research and here is the code that you're looking for. In InboxViewController.m to delete the message after it has been read, we have the following line: NSMutableArray *recipientId = [NSMutableArray arrayWithArray:[self.selectedMesssage objectForKey:@"recipientIds"]];

This says that we create a mutable array with the name recipientId and we create us by using an array located in the selected message with the key recipientIds on Parse. Meaning that the information on Parse is an array and in order to remove the current user's Id from that array, we have to create a mutable array using that stored array value so it can be edited. Once it is a mutable array we run this code:

 [recipientId removeObject:[[PFUser currentUser] objectId]];
 [self.selectedMesssage setObject:recipientId forKey:@"recipientIds"];
 [self.selectedMesssage saveInBackground];

The above code removes the current user's objectId from the mutable array. Then we set the key recipientIds with that updated information and then actually save it on Parse.

So that shows that it, in fact, an array.

I knew it was an array the whole time, the array of recipients. That's the whole point of my question, how can an array of recipientId's equal the current user's recipientId? This is stated in the following code:

// querying the messages class
PFQuery *query = [PFQuery queryWithClassName:@"Messages"];
// finding the recipients for the message, an Array, that are equal to the current user's Id, a String
[query whereKey: @"recipientIds" equalTo:[[PFUser currentUser] objectId]];

How does the second line of code ever return anything? A string cannot equal an array.

The string is inside of the array. That is what it is finding. I cannot fathom how you do not see what it is doing?

If the string is in the array stored on Parse, it returns the query.

Here it is in the documentation:

https://parse.com/docs/ios_guide#queries-arrays/iOS


Queries on Array Values

For keys with an array type, you can find objects where the key's array value contains 2 by:

// Find objects where the array in arrayKey contains 2.
[query whereKey:@"arrayKey" equalTo:@2];

It literally says it right in the documentation. "array value contains 2." Note the word contains and not "is equal to." Is that official enough?

No need to be hostile. It was just clearly obvious (and unimportant) to me and anyone is capable of reading documentation so I figured you had done that and just didn't see this information that is written as clear as day.

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Sorry I missed this discussion when it happened. As Eric linked, this query is built from the documentation (and by verifying that it works as expected with different values). I agree that a whereKey:contains: method makes more sense, but I chalk this up to a quirk in the Parse API. Perhaps a future update will add such a method.

Lol this is the first time you're producing actual evidence rather than "assuming."