PFUsers are sharing all the same PFObjects? - ios

Below are images to explain;
User 1 Logs in and sees the following based on the [PFUser currentUser].username;
However, if I register a new account and login as User 2 the same data is shared, and the name is changed in accordance to the [PFUser currentUser].username;
Im sure there is a method, but I'm not sure how exactly, on how do ensure any PFObjects being altered after logging in and securing a PFUser ID, are only associated with THAT user?

It works as expected. You should store the image along with the user that uploaded it. The label Uploaded by: *username* should be built with "Uploaded by: " + photoUploader.username not "Uploaded by: " + PFUser.currentUser.username

I was able to fix it by adding [query whereKey:#"user" equalTo:[PFUser currentUser]];
-(void)getReportImages{
//Fetch images
PFQuery *query = [PFQuery queryWithClassName:#"ReportImageObject"];
[query orderByDescending:KEY_CREATION_DATE];
[query whereKey:#"user" equalTo:[PFUser currentUser]];
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (!error) {
self.reportsObjectArray = nil;
self.reportsObjectArray = [[NSArray alloc] initWithArray:objects];
[self loadReportViews];
} else {
[self showErrorView:error];
}
}];
}

Related

Query PFRelation of blocked users

I'm trying to query the 'friend' relation while excluding any friends that have blocked the user (which is stored as a relation<_user>) on the friends user with a relation to the user they are blocking (potentially the user checking their friends). I tried querying like below, but it isn't excluding the record like I would think:
[SVProgressHUD showWithStatus:#"Loading ..."];
[friends removeAllObjects];
PFRelation *friendRelation = [[PFUser currentUser] objectForKey:#"friendsRelation"];
if (friendRelation)
{
PFQuery *friendsQuery = [friendRelation query];
[friendsQuery orderByAscending:#"firstname"];
[friendsQuery whereKey:#"disabled" notEqualTo:[NSNumber numberWithBool:YES]];
[friendsQuery whereKey:#"Blocked" notEqualTo:[PFUser currentUser]];
[friendsQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (!error)
{
friends = [objects mutableCopy];
[self.myTableView reloadData];
[SVProgressHUD dismiss];
}
else
{
[SVProgressHUD showErrorWithStatus:#"Loading failed. Please try again."];
}
}];
}
else
{
[SVProgressHUD dismiss];
}
Is there a way to accomplish what I am trying to do?
I had the same issue in one of my projects and solved it as follows. I created a class "blocked" and once a user blocks another user, I simply create two objects there. I did this in a general helper class, by creating a method (user1 is the current user, user2 is the other user):
void BlockUserOne(PFUser *user1, PFUser *user2)
{
PFQuery *query = [PFQuery queryWithClassName:PF_BLOCKED_CLASS_NAME];
[query whereKey:PF_BLOCKED_USER equalTo:[PFUser currentUser]];
[query whereKey:PF_BLOCKED_USER1 equalTo:user1];
[query whereKey:PF_BLOCKED_USER2 equalTo:user2];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
if ([objects count] == 0)
{
PFObject *object = [PFObject objectWithClassName:PF_BLOCKED_CLASS_NAME];
object[PF_BLOCKED_USER] = [PFUser currentUser];
object[PF_BLOCKED_USER1] = user1;
object[PF_BLOCKED_USER2] = user2;
object[PF_BLOCKED_USERID2] = user2.objectId;
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (error != nil) NSLog(#"BlockUserOne save error.");
}];
}
}
else NSLog(#"BlockUserOne query error.");
}];
}
This method creates an object in the blocked class, containing the two users that are part of the blocking process, as well as a third field with the user that initially did the blocking. This method is called two times, and user1 is always the current user:
PFUser *user1 = [PFUser currentUser];
BlockUserOne(user1, user2);
BlockUserOne(user2, user1);
This creates two objects in the blocked class (two because this makes handling both users being part of the blocking process easier)
Now, as the objects exist in the blocked class, it's time to check against them when querying for users. Here is an example of searching for users with a search bar:
- (void)searchUsers:(NSString *)search
{
PFUser *user = [PFUser currentUser];
//Querying for users that have been blocked by the current user
//or have blocked the current user (therefore the two different
//objects that I created
PFQuery *query1 = [PFQuery queryWithClassName:PF_BLOCKED_CLASS_NAME];
[query1 whereKey:PF_BLOCKED_USER1 equalTo:user];
//We don't want to query the current user, don't we?
PFQuery *query2 = [PFQuery queryWithClassName:PF_USER_CLASS_NAME];
[query2 whereKey:PF_USER_OBJECTID notEqualTo:user.objectId];
//
//This is the crucial part!!
[query2 whereKey:PF_USER_OBJECTID doesNotMatchKey:PF_BLOCKED_USERID2 inQuery:query1];
//
//
[query2 whereKey:PF_USER_FULLNAME_LOWER equalTo:[search lowercaseString]];
[query2 orderByAscending:PF_USER_FULLNAME];
[query2 setLimit:1000];
[query2 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
//Do whatever you want to do
}
else //Handle the error
}];
}
First, we query for all the users that have blocked the current user or have been blocked by the current user, and then we search for users that have not been returned by the first query.
This results in query2 returning users that have not been involved in a blocking process with the current user.
Hope this helps clearing up the situation.

Get all objects from one Parse class that are not mentioned in another class

I'm trying to query all records from confessions class whose author is not [PFUser currentUser]... but only those that our [PFUser currentUser] didn't rate on in ratings class.
confessions class:
ratings class:
Basically, I want to connect these two queries into one (somehow):
// get all confessions from other users
PFQuery *qConfessions = [PFQuery queryWithClassName:#"confessions"];
[qConfessions whereKey:#"author" notEqualTo:[PFUser currentUser]];
// get all ratings from this user
PFQuery *qRatings = [PFQuery queryWithClassName:#"ratings"];
[qRatings whereKey:#"ratedBy" equalTo:[PFUser currentUser]];
// get all qConfessions that are not in qRatings.confession
// YOUR HELP HERE :)
If there is no easy way to achieve what I want, do you think I should change the model and how? Should I just fetch all the ratings and then somehow ignore all qConfessions that are equal to ratings.confession? Any help would be welcome. Thank you.
Try this:
// get all qConfessions that are not in qRatings.confession
[qRatings whereKey:#"confession" doesNotMatchQuery: qConfessions];
[qRatings findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error == nil) {
} esle {
}
}];
I've made a workaround by adding a confessionId field to ratings class on Parse and using the following code:
// get all ratings from this user
PFQuery *qRatings = [PFQuery queryWithClassName:#"ratings"];
[qRatings whereKey:#"ratedBy" equalTo:[PFUser currentUser]];
// get all confessions from other users
PFQuery *qConfessions = [PFQuery queryWithClassName:#"confessions"];
[qConfessions whereKey:#"author" notEqualTo:[PFUser currentUser]];
// only fetch confessions that are not rated by current user
[qConfessions whereKey:#"objectId" doesNotMatchKey:#"confessionId" inQuery:qRatings];
// get all confessions from other users that are not rated by current user
[qConfessions findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// Success
} else {
// Error
}
}];

Parse.com query with relation

Im try to run this query in parse.com, But Everyone not working.
I have 2 tables, One for Promote and second for Archive.
So, I need to fetch all rows in Promote table where is not in archive table.
Like this
SELECT * FROM promote WHERE id NOT IN (SELECT promoteID FROM archive WHERE user=userID).
promoteID in archive is Pointer to objectId in Promote Table.
any help Please?
Try something like this....
PFQuery *innerQuery = [PFQuery queryWithClassName:#"Archive"];
[innerQuery whereKey:#"user" equalTo:[PFUser currentUser]];
[innerQuery orderByDescending:#"createdAt"];
PFQuery *query = [PFQuery queryWithClassName:#"Promote"];
[query whereKey:#"id" doesNotMatchQuery:innerQuery];
[query findObjectsInBackgroundWithBlock:^(NSArray *records, NSError *error) {
if (error) return;
for (PFObject *record in records) {
// .....
}
}];

Combining conditional queries isn't working properly?

I'm needing to use the parse.com method orQueryWithSubquerries: to create a combined conditional query.
Here is my code for it:
PFQuery *testQuery = [PFUser query];
[testQuery whereKey:#"displayName notEqualTo:#"Bob"];
PFQuery *testQuery2 = [PFUser query];
[testQuery whereKey:#"username" notEqualTo:#"frank"];
PFQuery *orQuery = [PFQuery orQueryWithSubqueries:#[testQuery, testQuery2]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
PFUser *user = [users firstObject];
}
}];
The code runs fine, but it returns all of my user objects, including the ones that should be filtered out from the 2 queries. Am I using this method wrong, or is there a certain way that I need to use it?
Edit:
I have also attempted to use this method exactly like how this parse.com example does, but it still doesn't work properly.
PFQuery *testQuery = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" greaterThan:#(3)];
PFQuery *testQuery2 = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" lessThan:#(1)];
PFQuery *orQuery = [PFQuery orQueryWithSubqueries:#[testQuery, testQuery2]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
// users still contains every user in the app even though it shouldn't according to the parse example
}
}];
You don't need to do a compound query, just query regularly:
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"displayName" notEqualTo:#"Bob"];
[userQuery whereKey:#"username" notEqualTo:#"frank"];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
PFUser *user = [users firstObject];
}
}];
You're confusing the use of a compound query, as you have it currently,
TestQuery = All users whose display isn't bob. (includes users whose username is frank)
TestQuery2 = All users whose username isn't frank. (includes users whose display name is Bob)
When you combine them, you get all of the users, your compound is contradictory.
Basically, all of the users left out in query1 are included in query2. And, all the users left out in query2 are included in query1. When you combine these queries, they fill in the missing space and you get all users.
Update
If you're trying to do hasPrefix, it seems like it should work fine:
NSString * prefixToSearch = ...;
PFQuery * displayNameQuery = [PFUser query];
[displayNameQuery whereKey:#"displayName" hasPrefix:prefixToSearch];
PFQuery * usernameQuery = [PFUser query];
[usernameQuery whereKey:#"username" hasPrefix:prefixToSearch];
PFQuery * compoundQuery = [PFQuery orQueryWithSubqueries:#[displayNameQuery, usernameQuery]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
NSLog(#"Found %i users", users.count);
}
}];
Update 2 - Let's Test
PFQuery *testQuery = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" greaterThan:#(3)];
PFQuery *testQuery2 = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" lessThan:#(1)];
PFQuery *orQuery = [PFQuery orQueryWithSubqueries:#[testQuery, testQuery2]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
// users still contains every user in the app even though it shouldn't according to the parse example
for (PFUser * user in users) {
int numberOfPhotos = [user[#"numberOfPhotos"] intValue];
if (1 <= numberOfPhotos && numberOfPhotos <= 3) {
NSLog(#"Query is failing");
}
}
}
}];
Update 3 - Predicates!
Via our conversation, we got it working with this:
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"keyOne BEGINSWITH 'z' OR keyTwo BEGINSWITH 'a'"];
PFQuery * userQuery = [PFQuery queryWithClassName:#"_User" predicate:predicate];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"Found objects: %#", objects);
}];
After looking into this once again I ended up changed my solution to being regex based rather than predicate. For my purposes that means I don't need to create an additional lowercase display name property since Parse regex allows for case-insensitive options. Also I can more easily change the parameters of the search with higher levels of flexibility.
My code now looks like this:
// Uses regex to remove white space at the beginning and end of search text
NSString *modifiedSearchText = [Utility stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:self.searchText];
PFQuery *userUsernameQuery = [PFUser query];
// the #"i" modifier is stated in the parse documentation and means case-insensitive
[userUsernameQuery whereKey:#"username" matchesRegex:modifiedSearchText modifiers:#"i"];
PFQuery *userDisplaynameQuery = [PFUser query];
[userDisplaynameQuery whereKey:#"displayName" matchesRegex:modifiedSearchText modifiers:#"i"];
PFQuery *userQuery = [PFQuery orQueryWithSubqueries:#[userUsernameQuery, userDisplaynameQuery]];
[userQuery orderByAscending:#"username"];
return userQuery;
In iOS 8.3, xcode 6.3.1
query.whereKey("name", matchesRegex:searchBar.text, modifiers:"i")
searches upper or lowercase words

Multiple Query Search with Parse.com

I'm trying to query to find specific users based on certain credentials.
The query will only look in the User class.
First, I want the query to match the currentUser's location
Second, must match a specific category (meaning multiple users in the same location may be under the same category)
Here's what I have tried:
self.profileObj = [self.currentUser objectForKey:#"city"];
PFQuery * queryOne = [PFUser query];
[queryOne whereKey:#"city" equalTo:self.profileObj];
PFQuery * queryTwo = [PFUser query];
[queryTwo whereKey:#"category" equalTo:self.tagString];
PFQuery * query = [PFQuery orQueryWithSubqueries:#[queryOne, queryTwo]];
[query orderByAscending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:(NSArrayobjects, NSError error)
This is returning 0 results.
You don't need two separate queries since you are querying on the same User object. Also, I believe you want two AND constraints rather than OR? If so, you can just chain together two whereKeys:
PFQuery * query = [PFQuery queryWithClassName:#"User"];
[query whereKey:#"city" equalTo:self.profileObj];
[query whereKey:#"category" equalTo:self.tagString];
[query orderByAscending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
...
}];

Resources