How to delete objects from an array stored in Parse column - ios

So , I've made a class called Posts in Parse.com.. This is the image of the class Posts
here you can see in objectId column there are objectIds of all the Posts and in the column likes I'm saving the ObjectIds of users who is liking the post.. so basically if a user tap on unlike button the current user's Id should be deleted . this is my current code:
var query:PFQuery = PFQuery(className: "Posts")
query.whereKey("objectId", equalTo: postData.objectId!)
query.whereKey("likes", equalTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
object.deleteInBackground()
}
}
})
but it deletes the whole row not the user id of current user..

You can use removeObject:forKey: to only remove this single object from the array. After doing this, call saveInBackground to save the changes back to the server.
See also: https://www.parse.com/docs/ios/guide#objects-arrays

I believe you are storing userID in your likes array as strings instead of pointers.
In your code, the key "likes" is an array type, but you want to query an objectId which is a string type, clearly parse won't find any column matches this query.
so in your case, you want to remove one of the strings in your likes array(objective c code)
PFQuery *query = [PFQuery queryWithClassName#"Posts"];
[query whereKey:#"objectId" equalTo:postData.objectId];
[query findObjectsInBackgroundWithBlock:^(NSArray *object, NSError *error)
{
if (! error)
{
//get the post object, index 0 because each post has 1 unique ID
PFObject *thisObject = [object objectAtIndex:0];
//get the likes array
NSMutableArray *array = [[NSMutableArray alloc]initWithArray:thisObject[#"likes"]];
[array removeObject:/* your user id*/];
//save the new array
[thisObject setObject:array forKey:#"likes"];
[thisObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error){
if (succeeded)
{
//success
}
}];
}
}];

I have used your method to remove a users objectID from another users friends list and instead add it to the users blocked friends list, both are in an array on parse. Thanks
let cell = tableView.cellForRow(at: indexPath) as! cell
let theUsersID = cell.theObjectID.text!
PFUser.current()?.addUniqueObjects(from: [theUsersID], forKey: "friendList")
PFUser.current()?.saveInBackground()
PFUser.current()?.removeObjects(in: [theUsersID], forKey: "blockFriend")
PFUser.current()?.saveInBackground()
self.usernames.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)

Related

Limiting Parse Query

I would like to retrieve 5 users from Parse, with their latest image posted. But if they haven't posted an image yet, that column will be empty so I have set up my query like this:
func uu() {
let query = PFQuery(className: "_User")
query.includeKey("latestImage")
query.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock { (object:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in object! {
if (object.objectForKey("latestImage") != nil)
{
self.lastPicArray.append(object.objectForKey("latestImage")!.valueForKey("image") as! PFFile)
self.profilePicArray.append(object.valueForKey("profilePicture") as! PFFile)
self.fullnameArray.append(object.valueForKey("firstname") as! String)
self.usernameArr.append(object.valueForKey("username") as! String)
}
}
self.collectionView.reloadData()
print(self.usernameArr)
print(self.lastPicArray)
}
}
}
As you'll see I have added the query.limit = 5 because when I do it seems to get them in some kind of order...And if in that order some users don't have anything in the lastPic column nothing shows...But what I need it to do is find all the users with something in that column and then limit them to 5...At the moment my code is doing all that apart from limiting them to 5!
If anyone knows how do fix this, I really appreciate any help!
I haven't worked with Swift but it is how it will work for you in objective C, you need to incorporate "whereKeyDoesNotExist" in your query and add limit to it. Following is the working code:
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query whereKeyDoesNotExist:#"latestImage"];
query.limit = 5;
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
NSLog(#"Got 5 objects");
}];

How to implement friend add/remove functionality in an iOS app using parse database?

I am trying to implement functionality to store data about user's friends (request friend, received friend request, accepted request). I have two tables.
First table is _User with username column.
Second table is Friends. This table is keeping track of who are friends of the user. This table has two fields:
A pointer column to user table
An array column called receivedRequest. In this array I keep the _User's objectId who are send request to that user.
Table _User has one to one relation with Friends table but meanwhile there is an array field keeping information of user's friend. In this array I am saving objectId of other users. I am using an array to avoid repeating rows for each friend's request.
Fist I want to know if this is a good idea or there is any alternative better that this. Actually I have extra array columns which is recived requests. Send requests. And accepted requests. All of them are array.
Second I want to know how can I write a query to go to Friends table. Find current user row. Go to friendList column. Return name of each friends whose name is in that array?
Currently I am doing this:
- (PFQuery *)queryForTable {
//Query user's friend request
PFQuery *query = [PFQuery queryWithClassName:#"Friends"];
[query whereKey:#"user" equalTo:[PFUser currentUser]];
[query includeKey:#"receivedRequest"];
return query;
}
This is returning only Id of the use's added my current user. I need their name from _User table.
Here's what I'd do:
(1) the User class ought to be about the user's relationship with the app, a place for data that's just between the user and the app.
(2) For data that users want to share, have a Persona class that has an image, nickname, etc. Persona should contain a pointer to User and vice versa.
(3) Personae (Personas in common usage) make friend invitations and become friends.
(4) arrays of string object ids = bad, arrays of pointers = good. In fact, I can't think of a circumstance where I'd prefer a string object id over a pointer.
(5) A FriendInvitation ought to be its own object, where inviter and invitee are pointers to Persona.
(6) A friendship is a bilateral and symmetrical relationship (at least we always hope they are). A good representation for that might be a Friendship class that has an array of pointers to exactly two Persona objects.
Here are a few functions, given a data model:
Persona has a pointer to User, call it 'user', and User has a persona pointer. FriendInvitation has an inviter and invitee, both pointers to Persona. Friendship has an array of two pointers to Persona, call it friends
// get the current user's FriendInvitations
- (void)friendInvitationsWithCompletion:(void (^)(NSArray *, NSError *))completion {
PFObject *persona = [PFUser currentUser][#"persona"];
PFQuery *query = [PFQuery queryWithClassName:#"FriendInvitation"];
[query whereKey:#"invitee" equalTo:persona];
[query includeKey:#"inviter"];
[query findObjectsInBackgroundWithBlock:completion];
}
// get the current user's friendships
// remember, these are not the friends, but the objects that record pairings of friends.
// see the next function for the friends
- (void)friendshipsWithCompletion:(void (^)(NSArray *, NSError *))completion {
PFObject *persona = [PFUser currentUser][#"persona"];
PFQuery *query = [PFQuery queryWithClassName:#"Friendship"];
[query whereKey:#"friends" equalTo:persona];
[query includeKey:#"friends"];
[query findObjectsInBackgroundWithBlock:completion];
}
// get the current user's friends' personae
- (void)friendsWithCompletion:(void (^)(NSArray *, NSError *))completion {
PFObject *persona = [PFUser currentUser][#"persona"];
[self friendshipsWithCompletion:^(NSArray *friendships, NSError *error) {
if (!error) {
NSMutableArray *result = [#[] mutableCopy];
for (PFObject *friendship in friendships) {
NSArray *friends = friendship[#"friends"];
NSInteger indexOfFriend = ([friends indexOfObject:persona] == 0)? 1 : 0;
[result addObject:friends[indexOfFriend]];
}
completion(result, nil);
} else {
completion(nil, error);
}
}];
}
// agree to be friends with someone
- (void)becomeFriendsWith:(PFObject *)friend completion:(void (^)(BOOL, NSError *))completion {
PFObject *persona = [PFUser currentUser][#"persona"];
PFObject *friendship = [PFObject objectWithClassName:#"Friendship"];
friendship[#"friends"] = #[ persona, friend ];
[friendship saveInBackgroundWithBlock:completion];
}
// we could go on, but this should convey the basic ideas
Friends table should not have arrays, but single IDs (actually pointers). So for every incoming request or friendship, there should be a single, separate entry on the database. So your Friends object (or for a better name, Relationship, or Friendship, but that's my personal preference of course) should roughly have following properties:
first (_User)
second (_User)
type (String. Possible values: 'friends' or 'request', maybe even 'blocked')
And for every accepted request, make sure you are creating two entries, one with first=user1/second=user2 and one with first=user2/second=user1. While you could technically go without making double entries, it will just complicate things in the long run, making everything harder to maintain.

How can I query/retrieve a random object from a parse class using swift?

I've looked all over and have found no joy. I was wondering if someone could help me figure out how to retrieve a random object from a class on parse.com using swift in an iOS app. By no means am I asking someone to write my code, because then what would I learn, but I was wondering if someone could maybe provide a generic example that I could adapt to my project and future projects.
Let's say the class is called ParseClass, and I will need to populate three variables with data from the object in parse., A, B, C -- two with strings, one as an array of strings. Let's say there are ... idk ... 50 objects in the parse class, and I need to retrieve them one at a time randomly.
Logically, I get it ... I need to do a count of the objects in the parseclass, then get a random number from that count, and then use that number to retrieve the object somehow (either directly from parse using a skip random query limit 1, or maybe by getting all the objects into an array (whichever is the best/most efficient code). I just don't know how to format/write the code in swift. Any one think they could help me (and many others apparently) with some generic code I could adapt to my specific project??
Here is some generic code ... I can start it -- I got a basic idea of how it should be, I just don't know swift well enough to complete the block.
var A : String!
var B : [String]!
var C : String!
var query : PFQuery = PFQuery(className: "ParseClass")
query.findObjectsInBackgroundWithBlock {
(objects : [AnyObject]!, error : NSError!) -> Void in
//now what?
I've seen this in other questions here, but I don't know how to incorporate it.
let randomSkip = arc4random_uniform(count)
query.skip = randomSkip, and query.limit = 1.
Any help on this would be greatly appreciated.
Oh -- just saw this in another thread ... it's basically doing what I need, but in objective C and it looks like with only 2 variables... could someone help me rewrite in swift? Sorry to be so loquacious ... the burden of a novice. I promise as I grow more adept, I will help other novices most sympathetically. :-)
- (void)randomQuestion:(void (^)(NSString *question, NSArray *answers))completion {
PFQuery *countQuery = [PFQuery queryWithClassName:#"ParseClass"];
[countQuery countObjectsInBackgroundWithBlock:^(int count, NSError *error) {
NSInteger randomSkip = arc4random_uniform(count);
PFQuery *query = [PFQuery queryWithClassName:#"ParseClass"];
query.skip = randomSkip;
query.limit = 1;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if (objects.count) {
PFObject *ParseClassObject = objects[0];
NSString *A = ParseClassObject[#"A"];
NSArray *B = ParseClassObject[#"B"];
completion(A, B);
} else {
NSLog(#"no error, but no ParseClass objects found");
}
} else {
NSLog(#"there was an error %#", error);
completion(nil, nil);
}
}];
}];
}
ObjectHolder should be objectHolder, or objects because it's a parameter name.
Your count for arc4random_uniform would be objects.count.
Downloading the objects and randomly accessing them locally will be most efficient if you need to display all of them anyway. Multiple downloads isn't great.
You're going to run into size limits eventually as the download row count is limited. Perhaps you could download pages and treat the items in each page as a separate collection to view randomly...
So, you wouldn't be using skip or limit, you would just be accessing elements in the objects array.
Removing the items from the array after you've used them is easiest. Or you can randomly sort the array so you don't need to remove
One way you can do it is to set another key called e.g. questionsNumber and each question will be be in that questionNumbers row. And then query the number from the arc4random_uniform(count) so something like this:
var query = PFQuery(className: "ParseClass")
let randomNumber = arc4random_uniform(count)
var randomNumberCast = Int(randomNumber)
query.whereKey("questionNumber", equalTo: randomNumberCast)
query.getFirstObjectInBackgroundWithBlock { (object: PFObject!, error: NSError!) -> Void in
if error == nil {
let questions = object["questions"] as String //This will equal your question at random.
}
}

Retrieve SAVED objectID from Parse

Im trying to retrieve the objectId of my parse records. I can save and retrieve data ok, but having gone through all parse documents, Google, and SO, I can't seem to get a clear answer on how to get the id for accessing records before the main block without hard coding the objectId as in the tutorial from Parse.
getObjectInBackgroundWithId:#"SS8Cw7rT1h" <-------- Trying to retrieve object id to go here
Im saving data to parse inc objectId here (all good)
PFObject *scheme = [PFObject objectWithClassName:#"SchemeProvider"];
//Sections of class
scheme[#"schemeName"] = self.schemeName.text;
scheme[#"schemeRegistrationNumber"] = self.registrationNumber.text;
//Save then get object id of saved row
[scheme saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[scheme objectId];
NSLog(#"SCHEME ROW ID %#",[scheme objectId]);
}];
Retrieving from parse (all good) - except - can't get objectID before main block
PFQuery *queryScheme = [PFQuery queryWithClassName:#"SchemeProvider"];
//NSString *myobjectId = [queryScheme valueForKey:#"objectId"]; <------trying to retrive object id
[queryScheme getObjectInBackgroundWithId:#"SS8Cw7rT1h" block:^(PFObject *retrivedData, NSError *error) {
NSLog(#"All data = %#", retrivedData);
}];
I have just hit this problem and have an example for you in swift
There is a function that saves with a block in background
You can access the objectId while saving in the block thats run after saving it to the cloud
var foo = PFObject(className:"Foo")
foo["bar"] = "something"
foo.saveInBackgroundWithBlock(){(succeeded: Bool!, error:NSError!) in
if succeeded
{
self.fooLabel.text = foo.objectId
}
}
You could store the objectId for a certain object e.g in a data structure or with core data if you need it for later access
Otherwise you need to query the object with property values i guess
like seen here: https://www.parse.com/docs/ios_guide#queries-basic/iOS
Hope this helps

how to get most recently added parse.com object

Is there any way to do a query in Parse to get the most recently added PFObject type?
I know that I can do a query with a greater than criteria, but it would be very useful if there was a function to get the most recent object added when no date is known.
Just add a descending order on createdAt and get the first object:
PFQuery *query = [PFQuery queryWithClassName:#"YourClassName"];
[query orderByDescending:#"createdAt"];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
// code
}];
In Swift:
var query = PFQuery(className: "YourClassName")
query.orderByDescending("createdAt")
query.getFirstObjectInBackgroundWithBlock {(object: PFObject?, error: NSError?) -> Void in
// code
}
This may not address the use case in question. I often want to get back the objectId of the object i just added in code. While it might be automatically possible, i have missed any info in this regard. So i usually have my own unique identifier that i add, and then retrieve the object by that identifier in the async block.. thus getting the objectId..

Resources