Parse.com query with relation - ios

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) {
// .....
}
}];

Related

PFUsers are sharing all the same PFObjects?

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];
}
}];
}

How to access fields of a pointer's value on parse.com with iOS?

I am designing a database. According to documentation, when number of relationships are greater than 100 and there is extra fields, I must design a Join Table. I designed this Join Table by having two pointer value.
This pointer value is pointing to _User. Later I need only rows for currUser.
This pointer value is the objectId of another table which is an entity. My question is, how can I write a query to return objects for this table in queryfortable.
Let's say:
Table _User
Table Entity
Table Join ---> objectId Pointer1(_User) Pointer2(Event)
This look like this:
This is what I have tried so far:
First I tried in viewDidLoad to get array of invitedUser from cloud and later in queryForTable:
PFQuery *query = [PFQuery queryWithClassName:#"Event"];
[query whereKey:#"objectId" containedIn:_inviteList];
but I need to access _inviteList.objectId which is not possible!
I tried to use innerQuerry or relation query. but as I just started learning parse I am not able to implement this.
PFUser *friendPointer = [PFUser currentUser];
PFQuery *query2 = [PFQuery queryWithClassName:#"Event"];
[query2 whereKey:friendPointer containedIn:_inviteList];
return query2;
This also did not work for me.
PFQuery *innerQuery = [PFQuery queryWithClassName:#"Invite"];
[innerQuery whereKey:#"invitedUser" equalTo:[PFUser currentUser]];
query = [PFQuery queryWithClassName:#"Event"];
[query whereKey:#"user" matchesQuery:innerQuery];
return query;
I appreciate if anyone can help me to write this query or re-design my table in order to have access to this query.
Pleaser try this code and give me review
PFUser *user = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"Invite"];
[query whereKey:#"invitedUser" equalTo:user];
[query includeKey:#"invitedUser"];
[query includeKey:#"eventId"];
[query orderByDescending:#"updatedAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
for (PFObject *underobject in [objects reverseObjectEnumerator])
{
PFUser *user1 = underobject[#"invitedUser"];
NSLog(#"invitedUser is :%#",user1);
}
}
}];

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) {
...
}];

parse.com: How to compare pointer-keys with objects?

I am using the backend service parse.com for a iOS app and I have a problem with querying it properly. I need help with the method whereKey:matchesKey:inQuery;
I have this code:
//NOT WORKING
PFQuery *query1 = [PFQuery queryWithClassName:#"Object"];
PFQuery *query2 = [PFQuery queryWithClassName:#"ObjectsRelations"];
[query2 whereKey:#"user" equalTo:[PFUser currentUser]];
[query1 whereKey:#"objectId" matchesKey:#"objectPointer" inQuery:query2];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// No objects
}];
It is not working the way I want. I have tried several ways for it to compare the key "objectPointer" in class "ObjectsRelations" (which is a pointer to an instance of class Object) to the actual Object in query 1. I do not get any objects back, because the comparison does not work as I want, since the key objectId is just a string and the key objectPointer is a pointer to a Object.
When I run this code, I get the intended result, but this requires me to do two api-requests to get the actual objectId as a string!
//WORKING
PFQuery *query = [PFQuery queryWithClassName:#"Object"];
PFQuery *query2 = [PFQuery queryWithClassName:#"ObjectRelations"];
[query2 whereKey:#"user" equalTo:[PFUser currentUser]];
[query2 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
PFObject *firstObject = [((PFObject*)[objects firstObject]) objectForKey:#"objectPointer"];
[query whereKey:#"objectId" equalTo:firstObject.objectId];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
//Getting the objects correctly from the class Object!
}];
}];
How to do this with a single api-request? How to compare a instance of a Class to a pointer of a class with a query?
Something like this is what i want to do: (Pseudo Code)
[query1 where:SELF matches:#"objectPointer" inQuery:query2];
Any suggestions?
I just searched this exact same problem and there are a number of questions on the Parse forum regarding it:
Trouble with nested query using object_id
Assistance with relational query
Compare string to pointer in query with does not match key in query
The first one explains a hack to include an extra field (in this case) in your ObjectRelations class. This key/field would be a string that would be the objectId of the pointer. It would be in addition to the key/field that holds the pointer.
If you look through the questions you can see that as of now there doesn't seem to be an answer directly from Parse regarding this.
Instead of adding an additional column with type String to contain the objectID it points to, I would suggest to add a column on each object with type Pointer to point to the object itself. This would dramatically reduce the amount of the columns you have to add. The only downside is this must be done on Cloud Code.
At this question's scenario, you'll have two queries like:
//Inner query
//Library containing pointer<Deck> & pointer<User>
PFQuery * subscriptions = [PFQuery queryWithClassName:#"subscription"];
[subscriptions whereKey:#"User" equalTo:[PFUser currentUser]];
//Outer query
//Pull down a list of deckStore objects not included in the subscriptions for current user
PFQuery * decks = [PFQuery queryWithClassName:#"deckStore"];
Then instead of:
[decks whereKey:#"objectId" doesNotMatchKey:#"deckString" inQuery:subscriptions];
You can do this:
[decks whereKey:#"this" doesNotMatchKey:#"deck" inQuery:subscriptions];
Here's a sample of what the Cloud Code should be added:
Parse.Cloud.afterSave("Deck", function(request) {
var deck = request.object;
// To make sure this is the first time of "afterSave" of this object.
if (deck.createdAt.getTime() == deck.updatedAt.getTime()) {
// "this" is the column which contains the pointer of the object itself.
if (deck.get("this") == null) {
deck.set("this", deck);
deck.save();
}
}
}
I have the same problem. This is my solution:
PFQuery *query1 = [PFQuery queryWithClassName:#"tableClass"];
[query1 whereKey:#"objectId" equalTo:[(PFObject *)[object objectForKey:#"pointerField"] objectId]];
PFObject *obj1 = [query1 getObjectWithId:[(PFObject *)[object objectForKey:#"pointerField"] objectId]];
NSString *pointerName = [obj1 objectForKey:#"name"];

Resources