Calling values from a random row in Parse? - ios

I'm trying to figure out how to call values from all columns for each variable within a random row, and each row is denoted by its own specific objectId, which is the name of the column, on Parse. Here is where I've defined the values of the variables in each column:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var voteCount1 = PFObject(className: "VoteCount")
voteCount1["choices"] = 2
voteCount1["votes"] = Int()
voteCount1["votes2"] = Int()
voteCount1["optionName"] = String()
voteCount1["optionName2"] = String()
}
I've figured out how to make it so that a button will send a vote to a variable's vote count (defined as an Int) in the row of a specific object ID, but I don't know how to call polls from a random Object ID and send votes to the corresponding choices in that row. Here's my IBAction of adding votes to a variable of a specific object ID:
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
var query = PFQuery(className: "VoteCount")
query.getObjectInBackgroundWithId("BiEM17uUYT") {
(voteCount1: PFObject!, error: NSError!) ->Void in
if error != nil {
NSLog("%#", error)
} else {
voteCount1.incrementKey("votes")
voteCount1.saveInBackgroundWithTarget(nil, selector: nil)
}
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
let percent1 = votes * 100 / (votes + votes2)
let percent2 = votes2 * 100 / (votes + votes2)
self.pollResults1.text = "\(percent1)% (\(votes)) \(percent2)% (\(votes2))"
}
}
How do I call values from random rows?
UPDATE: I just tried the following re-written from objective-C but I'm not sure if it's right:
var query = PFQuery(className: "VoteCount")
query.findObjectsInBackgroundWithBlock {
(objects: NSArray, error: NSError!) -> Void in
if error == nil {
randNumber = arc4random_uniform(count)
query2.whereKey("voteNumber", equalTo:randNumber)
query2.getFirstObjectInBackgroundWithBlock {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
let option1 = voteCount1["optionName"] as String
let option2 = voteCount1["optionName2"] as String
self.showOption1.text = "\(option1)"
self.showOption2.text = "\(option2)"
}
}
}

You would never hard-code object ids in your code. In order to fetch a random row, simply fetch all of the rows from Parse and then select one at random.
For example
PFQuery *query = [PFQuery queryWithClassName:#"VoteCount"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSInteger index=arc4random_uniform(objects.count);
NSLog("The random object is %#",objects[index]);
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
For a more useful implementation you would probably store the objects array into a property so that you could refer to it from outside the block.
Note that by default, only the first 100 rows will be returned. You can increase the limit up to 1000. Beyond 1000 you have to use paging with multiple queries. See https://parse.com/questions/fetch-all-data-in-a-table-using-pfquery
var query = PFQuery(className: "VoteCount")
query.findObjectsInBackgroundWithBlock {
(objects: NSArray, error: NSError!) -> Void in
if error == nil {
if let randomObject=objects[arc4random_uniform(objects.count)] {
println("The random object is \(randomObject)\")
}
} else {
println("error \(error)")
}
}

Related

Is it possible to query dictionary on parse.com?

i’m trying to search dictionary match result but no luck
my parse dictionary column look like this
columnName: Tag property: object
{"firstKey”:”David”,”secondKey”:”Guetta”}
columnName: name property: string
cool

when I try to search name column
here is my code snippet,
static func parseQueryDictionary() {
let query = PFQuery(className:"TestDictionary")
query.whereKey("name", equalTo: "cool")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil && objects != nil {
print("objects is", objects)
} else {
print(error)
}
}
}
i get result below
objects is Optional([ {
Tag = {
firstKey = David;
secondKey = Guetta;
};
name = cool;
tagArray = (
David,
Guetta
);
}])
i've try array column
columnName: tagArray property: array
["David","Guetta"]
static func parseQueryDictionary() {
let query = PFQuery(className:"TestDictionary")
query.whereKey("tagArray", equalTo:"David")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil && objects != nil {
print("objects is", objects)
} else {
print(error)
}
}
}
i get result
objects is Optional([ {
Tag = {
firstKey = David;
secondKey = Guetta;
};
name = cool;
tagArray = (
David,
Guetta
);
}])
but when i try to search dictionary column
columnName: Tag property: object
{"firstKey”:”David”,”secondKey”:”Guetta”}
like this
static func parseQueryDictionary() {
let query = PFQuery(className:"TestDictionary")
query.whereKey("Tag", equalTo:"David")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil && objects != nil {
print("objects is", objects)
} else {
print(error)
}
}
}
i get no result
objects is Optional([])

i’ve try google and parse official doc but can’t find this case, is it possible to do that?
i've try search string column, array column it's work but only dictionary column not work...
search in google with "findObjectsInBackgroundWithBlock" in swift.It will give you many results.
var query = PFQuery(className: parseClassName)
query.whereKey("Position", equalTo: "iOS Developer")//Here Position is column name and Sales Manager is value.
query.findObjectsInBackgroundWithBlock ({(objects:[AnyObject]!, error: NSError!) in
if(error == nil){
for object in objects {
}
}
else{
println("Error in retrieving \(error)")
}
})

How to create an array of usersnames when working with Parse and Swift

I am trying to create an array of strings for all the usernames using the following code and populate a TableViewController.
class TableViewController: UITableViewController {
var randomUser = [String]()
override func viewDidLoad() {
super.viewDidLoad()
var query: PFQuery = PFUser.query()!
query.findObjectsInBackgroundWithBlock {(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil{
if let objects = (objects as? [PFObject]!){
for object in objects{
self.randomUser.append(object.objectForKey("username") as! String)
print(object.objectForKey("username") as! String)
print(self.randomUser.count)
}
}
}
}
print(self.randomUser.count)
}
the output in the console:
0
username
1
username
2
username
3
But UItableview does not populate.. What could be causing this?
My guess is that query is delayed and view is created before it can return data. Thank you for any help!
Yes, you are right. You need to call self.tableView.reloadData() after you get the results of the query. Below is an example of where to call it.
private var usersArray = [PFUser]()
func fetchUsers() {
let userQuery: PFQuery = PFUser.query()!
userQuery.orderByAscending("username")
userQuery.whereKey("username", notEqualTo: (currentUser?.username)!)
userQuery.findObjectsInBackgroundWithBlock({
(users, error) -> Void in
if error == nil {
self.usersArray = users as! [PFUser]
self.tableView.reloadData()
} else {
print(error)
}
})
}
In this example, you can then access the username property by doing usersArray[i].username

Swift Parse - using PFQuery orQueryWithSubqueries function

I am looking at the Parse documentation, and there is this interesting function I would like to use to make validate for signing up users if the username and email provided are registered (taken) or not. The documentation provides example for the following:
var lotsOfWins = PFQuery(className:"Player")
lotsOfWins.whereKey("wins", greaterThan:150)
var fewWins = PFQuery(className:"Player")
fewWins.whereKey("wins", lessThan:5)
var query = PFQuery.orQueryWithSubqueries([lotsOfWins, fewWins])
query.findObjectsInBackgroundWithBlock {
(results: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// results contains players with lots of wins or only a few wins.
}
}
my version of it is:
/*Check username and email not taken*/
let usernameInputCheck = PFQuery(className:"_User")
usernameInputCheck.whereKey("appUsername", equalTo: self.usernameTxtField.text!)
let emailInputCheck = PFQuery(className:"_User")
emailInputCheck.whereKey("email", equalTo:self.emailTxtField.text!)
let query = PFQuery.orQueryWithSubqueries([usernameInputCheck, emailInputCheck])
query.findObjectsInBackgroundWithBlock {
(results: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// results contains players with lots of wins or only a few wins.
}
}
I want to be able to check if email or username is taken, and if yes set a flag so that I can set message to user saying for example: "Email provided is already registered" or "Username is not available, try a different one".
Thanks for your help in advance.
Update: Here is the link to Parse docs: https://parse.com/docs/ios/guide#queries-compound-queries
Here is some objective-c that does the trick, which you could easily adapt to Swift.
PFQuery * nameQuery = [PFQuery queryWithClassName:#"user"]
[nameQuery whereKey:"username" equalTo:username];
PFQuery * emailQuery = [PFQuery queryWithClassName:#"user"];
[emailQuery whereKey:"email" equalTo:email];
PFQuery * query = [PFQuery orQueryWithSubqueries:#[nameQuery, emailQuery]
[query countObjectsInBackgroundWithBlock:^(int number, NSError *error) {
if(number > 0) {
//Email address OR username is already in use.
}
}];
Workaround the problem:
let usernameInputCheck = PFQuery(className:"_User")
usernameInputCheck.whereKey("appUsername", equalTo: self.usernameTxtField.text!)
let emailInputCheck = PFQuery(className:"_User")
emailInputCheck.whereKey("email", equalTo:self.emailTxtField.text!)
let query = PFQuery.orQueryWithSubqueries([usernameInputCheck, emailInputCheck])
query.findObjectsInBackgroundWithBlock {
(results: [PFObject]?, error: NSError?) -> Void in
if error == nil {
let checkResult = self.emailOrUsernameIsTaken(results!)
if(checkResult != 0 && checkResult == 1)
{
//username taken
}else if (checkResult != 0 && checkResult == 2){
//email taken
}
}
}
and here is the function:
func emailOrUsernameIsTaken(results: [PFObject])->Int
{
/*Check if username is taken or if email is taken*/
var preferenceTaken: Int = 0
if(results[0]["email"] as! String != "" && results[0]["email"] as! String == self.userObject.email!)
{
preferenceTaken = 1
}else if(results[0]["appUsername"] as! String != "" && results[0]["appUsername"] as! String == self.userObject.username!){
preferenceTaken = 2
}
return preferenceTaken
}

How can I get more than 1000 results from a Parse query?

I've been trying to chain to no success. After an initial query, I attempt to count the results. Then, I check to see if the results are equal to the limit of the query. If they are the same, I create a new query and repeat.
All I'm getting is the results of the first query, however.
Code is here:
var allObjects = [PFObject]()
var skip = 0
var limit = 10
var downloadCards = PFQuery(className: "Checklist")
downloadCards.whereKey("createdBy", equalTo:PFUser.currentUser()!)
downloadCards.includeKey("card")
downloadCards.orderByAscending("IndexNumber")
downloadCards.limit = limit
downloadCards.skip = skip
downloadCards.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFObject] {
for object in objects {
if let card = object["card"] as? PFObject {
allObjects.append(card)
}
}
}
//1000
if objects!.count == limit {
//Query again until results aren't equal to limit
skip = skip + limit
var downloadCards2 = PFQuery(className: "Checklist")
downloadCards2.whereKey("createdBy", equalTo:PFUser.currentUser()!)
downloadCards2.includeKey("card")
downloadCards2.orderByAscending("IndexNumber")
downloadCards2.limit = limit
downloadCards2.skip = skip
downloadCards2.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFObject] {
for object in objects {
if let card = object["card"] as? PFObject {
allObjects.append(card)
}
}
}
You can set the "skip" variable to 1,000, 2,000, etc. as you get more results up to 10,000 skips. After that, you can follow the directions here: https://parse.com/questions/paging-through-more-than-10000-results
Edit:
Apologies - I might have misread your question.
1) You should rename the variables in your second loop to objects2, error2, card2, etc. similar to downloadCards2.
2) Alternatively, to make your code scalable and DRY, I would make allObjects, skip, and limit properties and simply re-run the same query again.
func runQuery() {
var downloadCards = PFQuery(className: "Checklist")
downloadCards.whereKey("createdBy", equalTo:PFUser.currentUser()!)
downloadCards.includeKey("card")
downloadCards.orderByAscending("IndexNumber")
downloadCards.limit = limit
downloadCards.skip = skip
downloadCards.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFObject] {
for object in objects {
if let card = object["card"] as? PFObject {
allObjects.append(card)
}
}
}
if objects!.count == limit {
skip = skip + limit
self.runQuery()
}
}
}
}

Re-accessing random data between methods in ViewController

For my Swift app, I want the data accessed in the didReceiveMemoryWarning function to be from the same random column of data retrieved from the viewDidLoad function, which was done with let randNumber = Int(arc4random_uniform(UInt32(count))). My app is a poll app where users can vote for different poll options then when they click the "Next" button, it takes them to another poll at random. The code under the didReceiveMemoryWarning function is for adding the vote (and retrieving it) from a poll, but I need that poll to be the same one displayed by the viewDidLoad function. How do I do that? For some reason no matter what poll I retrieve (crepes or pancakes, Coke or Pepsi, chocolate or vanilla, etc.) it only adds votes to and retrieves the results from the "crepes or pancakes" poll. Like if the user gets the poll "Coke or Pepsi" and they select Coke, it'll add a vote to the crepes vote count and retrieve the results from that poll. How do I retrieve data from the poll that is retrieved?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var query = PFQuery(className: "VoteCount")
query.countObjectsInBackgroundWithBlock {
(count: Int32, error: NSError!) -> Void in
if error == nil {
let randNumber = Int(arc4random_uniform(UInt32(count)))
query.whereKey("pollNumber", equalTo: randNumber)
query.getFirstObjectInBackgroundWithBlock {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
let option1 = voteCount1["optionName"] as String
let option2 = voteCount1["optionName2"] as String
self.showOption1.text = "\(option1)"
self.showOption2.text = "\(option2)"
}
}
} else {
println("error \(error)")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var pollResults: UILabel!
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
var query = PFQuery(className: "VoteCount")
query.getFirstObjectInBackgroundWithBlock {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
voteCount1.incrementKey("votes")
voteCount1.saveInBackgroundWithTarget(nil, selector: nil)
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
self.pollResults.text = "\(votes) \(votes2)"
}
}
}
You could make randomNumber a property instead of a local variable. However I think what you're actually trying to do is make sure you access the same PFObject in your later methods as you do in viewDidLoad. To do this, you don't need to re-fetch from Parse. Just keep a reference to the PFObject:
var voteCount : PFObject?
And in your completion block in viewDidLoad:
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
self.voteCount = voteCount1
// The rest of your code...
let votes = voteCount1["votes"] as Int
Then, later on, instead of fetching again, you just use the voteCount property:
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
voteCount.incrementKey("votes")
voteCount.saveInBackgroundWithTarget(nil, selector: nil)
let votes = voteCount["votes"] as Int
let votes2 = voteCount["votes2"] as Int
self.pollResults.text = "\(votes) \(votes2)"
}

Resources