Trying to do two Parse PFQueries but getting error - in SWIFT - ios

I am currently doing two PFQueries at once, one which is a PFUser.query and one which is a standard object query. These are both trying to execute roughly at the same time. I get no errors in the code until it runs it says:
'Cannot do a comparison query for type: Swift._NSSwiftArrayImpl'
I can only assume this is because I am trying to do two different queries at once?
Can somebody add some input into what it means a bit more and how maybe to overcome it?
the code I have used for both queries is:
var query = PFQuery(className: "Traits")
query.whereKey("name", equalTo: self.names)
var waveUsers = query.findObjects()
if waveUsers != nil {
self.profile.waves.removeAll(keepCapacity: true)
for waveUser in waveUsers{
self.profile.waves.append(waveUser["waves"] as Int)
}
}
and the PFUser Query:
var query = PFUser.query()
query.whereKey("location", nearGeoPoint:geopoint)
query.limit = 20
var users = query.findObjects()
if users != nil {
self.profile.names.removeAll(keepCapacity: true)
self.profile.images.removeAll(keepCapacity: true)
self.profile.genders.removeAll(keepCapacity: true)
self.profile.locations.removeAll(keepCapacity: true)
self.profile.status.removeAll(keepCapacity: true)
self.profile.rStatus.removeAll(keepCapacity: true)
self.profile.age.removeAll(keepCapacity: true)
for user in users {
{
self.profile.names.append(user["name"] as Int)
self.profile.images.append(user["image"] as NSData)
self.profile.genders.append(user["gender"] as NSString)
self.profile.locations.append(user["location"] as PFGeoPoint)
self.profile.rStatus.append(user["relationship"] as NSString)
self.profile.age.append(user["age"] as NSInteger)
self.profile.status.append(user["status"] as NSString)
self.appsTableView.reloadData()
user.save()
}
}
thanks in advance

If you want to test whether the "name" col can be found in your self.names array, then use containsAllObjectsInArray:
equalTo operates on single objects (it can test for a single object's presence in an array type column, but you're attempting the other way around).
EDIT - Lets say you have an array of strings, and you'd like to find objects whose string column an be found in the array...
// find people in the People class who were SNL cast members
var array = ["belushi", "akroyd", "radner"];
var queries = [];
// assume underscorejs
_.each(array, function(name) {
var query = new Parse.Query("People");
query.equalTo("lastName", name);
queries.push(query.find());
});
Parse.Query.or(queries).then(function() {
var snlCastMembers = _.toArray(arguments);
});

Related

Adding integers in for loop and printing the total

I am looping through integer objects and want to add each integer to an integer variable, then when the for-loop is done, print the total. Is there an easy way to do this? Right now, I can retrieve the objects and print them individually, but the total prints as 0 every time.
Please see the code below. This is for an app written in Swift with Parse as the backend.
Anything helps, and thank you!
var itemsArray = [Int]()
let followingUserItemsQuery = PFUser.query()
followingUserItemsQuery?.whereKey("objectId", equalTo: (PFUser.currentUser()?.objectId!)!)
followingUserItemsQuery?.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error) in
if let objects = objects {
for object in objects {
let followingUsersArray = (object["following"] as! [String])
// Get number of listed items of following users with PFUser query for their total objects
for followingUser in followingUsersArray {
print(followingUser)
let query = PFUser.query()
query?.whereKey("objectId", equalTo: followingUser)
//Get each user's listedItems count then append to a higher-level integer variable
query?.getFirstObjectInBackgroundWithBlock({ (object, error) in
itemsArray.append(object!["listedItems"] as! Int)
})
}
}
}
let itemsSum = itemsArray.reduce(0, combine: +)
print(itemsSum)
self.followingUsersAddedItems.text = String("Your followers listed "+String(itemsSum)+" items")
Try this:
var count = 0
...
for followingUser in followingUsersArray {
count += object!["listedItems"] as! Int
}
Your code to reduce / combine the Int values is correct. The problem is that it runs before any of the nested asynchronous Parse queries complete and execute their callbacks. So at the time it runs, itemsArray is still empty. You will need to redesign your code so that itemsSum is calculated only after all the various nested Parse queries have all completed.

Two constraints on one key in a Parse Query

I'm using Parse and my app is written in Swift. I have a golf app that allows a user to friend other users. The users can log their golf scores and then see their golf scores and their friend's scores in a leaderboard style tableViewController.
The problem I'm having is that Parse doesn't support two constraints on the same key in a query. I have a function that queries the users and their scores and stores them in an array of tuples (leadeboardData). I'm trying to querying the current user's PFRelation as well as the current user (variable "friendsRelation" and constant "friendQuery"). The class I query is the "GolfScorecard", which is where the scores are stored on Parse. I then called the "whereKey" method on the "golfer" key, which is where my user is stored under on Parse. I call "whereKey matchesQuery" for my friendsRelation query and then "whereKey equalTo" to try and get my current user. I then "includeKey" "golfer" so I can get the user info along with the score info. Any suggestions on how to go about this? I'm trying to do it all in one query but when the "whereKey" method is called on the same key ("golfer") the last one overrides the first one, which makes it only possible to get the friend info or the current user info but not both. I'm stumped how to include both. Thanks in advance.
Here is my function I call to make the query:
func loadLeaderboardData() {
leaderboardData.removeAll()
friendsRelation = PFUser.currentUser()?.objectForKey("friendsRelation") as? PFRelation
friendsRelation = PFUser.currentUser()?.objectForKey("friendsRelation") as? PFRelation
let friendQuery = friendsRelation?.query()
let query = PFQuery(className: "GolfScorecard")
query.whereKey("golfer", matchesQuery: friendQuery!)
query.whereKey("golfer", equalTo: PFUser.currentUser()!)
query.includeKey("golfer")
query.orderByAscending("score")
query.findObjectsInBackgroundWithBlock { (scoreCards: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object:PFObject in scoreCards! {
let golfer:PFObject = object["golfer"] as! PFObject
self.leaderboardData.append(object,golfer)
dispatch_async(dispatch_get_main_queue()) {
self.leaderboardTableView.reloadData()
}
}
} else {
print(error)
}
}
}
Thanks Paulw11 the orQueryWithSubQueries worked. The only issue it ended up presenting was my app was crashing with an error stating 'Key "username" has no data. Call fetchIfNeeded before getting its value.'...I don't think the Parse Query was coming back in time to load in the tableView that I was putting the data in. I ended up using the 'fetchIfNeededInBackgroundWithBlock' method inside of the cellForRowAtIndexPath call around the code where I was calling the 'username' data at. This allowed it to grab the data in the background if it didn't come back in time. This seemed to due the trick.
-Also I subclassed my queries, which is where the GolfScorecard & GolferProfile is coming from inside of my for-in loop.
-This is my new compound Query:
func loadLeaderboardData() {
leaderboardData.removeAll()
friendsRelation = PFUser.currentUser()?.objectForKey("friendsRelation") as? PFRelation
let friendQuery = friendsRelation?.query()
let friendScorecardQuery = PFQuery(className: "GolfScorecard")
friendScorecardQuery.whereKey("golfer", matchesQuery: friendQuery!)
let currentUserScorecardQuery = PFQuery(className: "GolfScorecard")
currentUserScorecardQuery.whereKey("golfer", equalTo: PFUser.currentUser()!)
let subQuery = PFQuery.orQueryWithSubqueries([friendScorecardQuery, currentUserScorecardQuery])
subQuery.orderByAscending("score")
subQuery.findObjectsInBackgroundWithBlock { (scoreCards: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object:PFObject in scoreCards! {
if let object = object as? GolfScorecard {
let golfer = object["golfer"] as! GolferProfile
self.leaderboardData.append(object,golfer)
dispatch_async(dispatch_get_main_queue()) {
self.leaderboardTableView.reloadData()
}
}
}
} else {
print(error)
}
}
}

PFQuery where array of pointers contains a certain PFObject

Objects in my class Deal have an attribute relatedContacts which is an array of pointers to Contact objects. I'm running the following query to determine whether the current Contact object is the target of a pointer in any Deal, prior to deleting the Contact.
let relatedContactObjects:NSArray = [self.contactObject] as NSArray
let relatedContactQuery:PFQuery = PFQuery(className: "Deal")
relatedContactQuery.fromLocalDatastore()
relatedContactQuery.fromPinWithName("Deals")
relatedContactQuery.whereKey("user", equalTo: PFUser.currentUser()!)
relatedContactQuery.whereKey("relatedContacts", containsAllObjectsInArray: relatedContactObjects as [AnyObject])
However this returns Parse Error 102: "Value type not supported for $all queries."
The Parse documentation says that containsAllObjectsInArray takes an NSArray, but Xcode shows a warning that NSArray is not implicity convertible to [AnyObject].
Any ideas how I can make this query work?
Edit: I looked at the contents of relatedContacts and it seems that each instance contains an array of dictionaries, example: [{"__type":"Pointer","className":"Contact","objectId":"BoLym053hX"},{"__type":"Pointer","className":"Contact","objectId":"AgpnxAFUBn"},{"__type":"Pointer","className":"Contact","objectId":"ob20tThdfp"}]
As suggested, I've also looked at the containedIn query constraint, but that is used to identify objects that are contained in a given array. I am trying to identify arrays that contain a given object.
Parse.com overloads equalTo: by allowing it to mean either: (a) a singular property equals the operand, or (b) an array property contains the operand. So you're objective is easily stated as follows:
relatedContactQuery.fromPinWithName("Deals")
relatedContactQuery.whereKey("user", equalTo: PFUser.currentUser()!)
relatedContactQuery.whereKey("relatedContacts", equalTo:self.contactObject)
Prior to the accepted answer, I also tried using loops to go through the arrays and identify whether they contained the current object, then incremented a count.
var dealsPointingToContactCount:Int = 0
func countDealsRelatedToContact() {
let dealsWithRelatedContactQuery:PFQuery = PFQuery(className: "Deal")
dealsWithRelatedContactQuery.fromLocalDatastore()
dealsWithRelatedContactQuery.fromPinWithName("Deals")
dealsWithRelatedContactQuery.whereKey("user", equalTo:PFUser.currentUser()!)
dealsWithRelatedContactQuery.whereKeyExists("relatedContacts")
dealsWithRelatedContactQuery.findObjectsInBackgroundWithBlock{(objects, error) -> Void in
if (error == nil) {
var dealsWithPointersToContacts:NSArray = objects! as NSArray
for deal in dealsWithPointersToContacts {
var dealContactsArray:NSArray = deal["relatedContacts"] as! [PFObject]
for contact in dealContactsArray {
if contact as! PFObject == self.object {
self.dealsPointingToContactCount++
println("Deals pointing to current contact: \(self.dealsPointingToContactCount)")
}
}
}
}
}
}

How to store retrieved data to the another class in Parse

I've a small problem. I am working on an App using Parse backend. So my problem is:
i've retrieved all the objectIds of users in _User class like this:
var userIds = [String]()
var userQuery = PFUser.query()
userQuery?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.userIds.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
if user.objectId != PFUser.currentUser()?.objectId {
self.userIds.append(user.objectId!)
}
}
}
}
println(userIds)
})
Now i want to save all the userIds which are stored in the array "userIds" to a column in a class named "Something". so the code will be like:
var something:PFObject = PFObject(className: "Something")
something["users"] = // have problem here
something.saveInBackground()
if i put userIds here, it gives an error.. because userIds is an array but column "users" is String.. but also i want to save all the userIds seperately in the column "users" like it is saved in objectId column of _User class..
I'm new here and I can't comment in the reply where you asked for help. Anyway, what do you want now is save only new users, as you said:
I just want to save the users which are not there
Well, there are some suggestions:
You can retrieve your User class and check for new users manually in the app and then send the new ones to your Class.
You can create a new column in your User class like "saved" where contains a boolean indicating if you already saved this user to your custom class or not. Remember also, of always do
user["saved"] = false
while creating a new user and then simply do:
let search = PFQuery(className: "_User")
search.whereKey("saved", equalTo: false)
to get these non saved users.
I strongly recommend the second option.
Ok, the case that you describe should look something like this:
var userIds = [String]()
var userQuery = PFUser.query()
userQuery?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects as? [PFUser] {
var somethingObjects = [PFObject]()
self.userIds.removeAll(keepCapacity: true)
for user in users {
if user.objectId != PFUser.currentUser()?.objectId {
self.userIds.append(user.objectId!) // I don't know if this is necessary anymore for your usecase
var something:PFObject = PFObject(className: "Something")
something["users"] = user.objectId
somethingObjects.append(something)
}
}
PFObject.saveAllInBackground(somethingObjects)
}
})
In this case, you create a number of something objects that are saved, but you might want to rename the "users" column to "user", since you only save one objectId per row.
I haven't worked with parse in a while, so there might be a way to optimize the number of API calls you have to make.

Trying to split array of objects based on a common key of the objects with swift

I'm completely lost with swift. I am trying to split an array of objects (retrieved using the Parse SDK) based on a common key.
Basically I would like to make a COUNT + GROUP BY, but I could not find a way to make a GROUP BY with the Parse SDK, so I am trying to group the objects and count them by the code.
But first, what I am writing looks horrible, and secondly that does not even compile and I can't understand why.
This is the code I'm using
var groupedEntries = [String: [String: AnyObject?]]()
...
let query = PFQuery(className: "Entry")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
var groupingKey: String
for object in objects {
groupingKey = object[groupingKey] as String
if self.groupedEntries[groupingKey] != nil {
self.groupedEntries[groupingKey]["count"] = self.groupedEntries[groupingKey]["count"] + 1
} else {
self.groupedEntries[groupingKey]["count"] = 1
}
}
self.tableView.reloadData()
}
}
And the compiler gives the following error : 'String' is not convertible to 'DictionaryIndex'. Whatever I try I get an error related to optionals or wrapping.
Thanks to anybody that will help me :)
While using subscript the Dictionary returns optional of given value type so you need to unwrap it.You need to take the extra variable i used somevar.See below code
var groupedEntries = [String: [String: AnyObject?]]()
#IBAction func changeImage(sender: AnyObject){
var objects:[AnyObject]!
var groupingKey: String //= "abc" Intialize before using
//var countryCode: String //= "abc" not defined in your code
for object in objects {
groupingKey = object[groupingKey] as String
if self.groupedEntries[groupingKey] != nil {
var somevar = self.groupedEntries[groupingKey]!
somevar["count"] = (somevar["count"]! as Int) + 1
} else {
self.groupedEntries[groupingKey] = ["count":1]
}
}
}
I do not know about your logic but this code compiles well.

Resources