Simply: I want rating system of the post (or image) that works the same as in Yik Yak or 9gag - user can upvote or downvote only once the post. I dont want to store these data on device but everything on parse.com. I also would like to count the comments. Ideally do everything in only one query to parse.com
I am using currently this code but I dont think this is the good approach how to do it because for every image it will create a new query. Currently I have 4 tables in Parse.com User, Image, Comment, Rating and everything is connected with pointers to the image or user.
func loadData(){
forPaginationStart = 0
numberOfImagesPerPage = 5
imageData.removeAllObjects()
var findImageData: PFQuery = PFQuery(className: "Image")
findImageData.whereKey("deleted", equalTo: 0)
findImageData.orderByDescending("createdAt")
findImageData.skip = forPaginationStart
findImageData.limit = numberOfImagesPerPage
findImageData.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?, error:NSError?)->Void in
if error == nil{
for object in objects! {
let image:PFObject = object as! PFObject
self.imageData.addObject(image)
//comment counts
var countComments = PFQuery(className:"Comment_image")
countComments.whereKey("image_id", equalTo: PFObject(withoutDataWithClassName: "Image", objectId: "\(image.objectId!)"))
countComments.whereKey("deleted", equalTo: 0)
countComments.countObjectsInBackgroundWithBlock {
(count: Int32, error: NSError?) -> Void in
if error == nil {
println("There is \(count) comments for image: \((object.objectId!)!)")
self.commentCount.append(countComments.countObjects())
}
}
}
self.tableView.reloadData()
}
}
//count number of records in DB for pagination end
var totalNumOfRows: PFQuery = PFQuery(className: "Image")
totalNumOfRows.whereKey("deleted", equalTo: 0)
totalNumOfRows.countObjectsInBackgroundWithBlock {
(count: Int32, error: NSError?) -> Void in
if (error == nil) {
self.totalNumRecords = Int(count)
println("total records: \(self.totalNumRecords)")
}
}
}
I had it working with php and SQL but with parse the same approach doesnt work for me... I asked the DB what is the value for that user, if it was 1 the user upvoted and if negative one he downvoted, 0 neither one and I set the button according to the value
SQL query:
IFNULL((SELECT value FROM rating WHERE image.id = rating.image_id AND rating.user_id = (SELECT id FROM user WHERE uuid='$uuid')), 0) as UserRating
- (instancetype)whereKey:(NSString *)key matchesKey:(NSString *)otherKey inQuery:(PFQuery *)query
You can use this method on PFQuery, for example:
var countComments = PFQuery(className:"Comment_image")
var findImageData: PFQuery = PFQuery(className: "Image")
findImageData.whereKey("deleted", equalTo: 0)
findImageData.orderByDescending("createdAt")
findImageData.skip = forPaginationStart
findImageData.limit = numberOfImagesPerPage
countComments.whereKey("image_id", matchesKey:"objectId", inQuery: )
countComments.whereKey("deleted", equalTo: 0)
countComments.countObjectsInBackgroundWithBlock {
(count: Int32, error: NSError?) -> Void in
if error == nil {
println("There is \(count) comments for all images!")
}
}
By setting up the count query like this, you don't have to call count for each image, but I don't know in the background if Parse optimizes to make it faster than your current query.
Related
When trying to use a multitude of queries I'm getting all the results, its not actually filtering any data whatsoever. I have tried multiple ways to perform this and some reason I cannot get it to only show what I'm looking for.
func getOpenWorkOrders() {
let query1 = WorkOrders.query()!
query1.whereKey("status", equalTo: "New")
let query2 = WorkOrders.query()!
query2.whereKey("status", equalTo: "In Progress")
let query3 = WorkOrders.query()!
query3.whereKey("status", equalTo: "On Hold")
let query4 = WorkOrders.query()!
query4.whereKey("status", equalTo: "Assigned")
let query5 = WorkOrders.query()!
query4.whereKey("status", equalTo: "Ready To Bill")
let queries = PFQuery.orQueryWithSubqueries([query1, query2, query3, query4, query5])
queries.countObjectsInBackgroundWithBlock { (number : Int32, error : NSError?) in
if error == nil {
self.openWorkOrdersNumber.text = String(number)
}
}
}
is there something I am missing here?
This is the same way I'm doing it in the rest of my app
I am creating an app that involves questions and facts and I need them to be selected at random. There is going to be a ton of different ones and I do not want to have to type in the ObjectId for each one of them. Is there a way to get the ObjectId of a random row so I don't have to write in the object Id for each question or fact that is in the class?
Three steps to accomplish what you want:
Know ahead of time or find out the number of questions you have to look through.
Create a random integer using arc4random() or some other method between 0 and that number.
Create a PFQuery on your question class with skip set to the random integer and limit set to 1.
Here is a function for retrieving your questions, only the first 1000, and saving them locally:
func saveAllObjectsLocally() {
let query = PFQuery(className: “Questions”)
query.limit = 1000
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects {
do {
try PFObject.pinAllInBackground(objects)
} catch let error as NSError? {
print("error \(error)")
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
}
Once they are saved locally, a random question can be selected:
func getRandomQuestion() -> PFObject? {
let query = PFQuery(className: “Questions”)
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if let objects = objects {
let randomIndex = arc4random_uniform(UInt32(objects.count))
return objects[Int(randomIndex)]
}
}
return nil
}
This is going to be faster than accessing the network every time a random question is needed.
If you need to access the questions from the cloud you can add an index column to your Parse database and use that as a key to efficiently retrieve a random row.
I am developing app using ios, swift and parse.com as backend.
My problem is I need one query object result in second query object like below code. but when i use below code GUI become unresponsive for some time because of findObjects() method. I have used findObjectsInBackgroundWithBlock() instead but than tableview self.posts display only one record in tableview. I have 10 record in post table.
Can you guide me proper way how to resolve below issue.Actually I does not want to use findObjects() method.
var query = PFQuery(className:"Post")
var fquery = PFQuery(className: "Friends")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
let user = PFUser.currentUser()
if let objects = objects as? [PFObject] {
for object in objects {
friendArray.removeAll(keepCapacity: false)
fquery.whereKey("whosefriend", equalTo: object["postusername"])
var fobjects = fquery.findObjects()
for fobject in fobjects {
friendArray.append(fobject["friendname"] as String)
}
if (contains(friendArray, user["fullname"] as String)) {
let post = Post(.......)
self.posts.append(post)
}
}
}
self.tableView.reloadData()
} else {
println("Error: \(error) \(error.userInfo!)")
}
}
One option is to make your "postusername" a pointer column in class Post that points to Friends class and then you would only need one query that would go something like:
var query = PFQuery(className:"Post")
query.includeKey("postusername") //this would include the object that it points to i.e. the Friends object you saved there
... then in your for loop ...
for object in objects! {
let friend = object["postusername"] // now friend is the Friends object
let friendName:String = friend["friendname"] as? String
friendArray.append(friendName)
}
Note: this requires you saving "postusername" as a PFObject of Class Friends. Parse iOS docs explain this well.
https://parse.com/docs/ios/guide
I have resolve the issue by using relational query.
var query = PFQuery(classWithName: "Post")
var fQuery = PFQuery(className:"Friends")
fQuery.whereKey("friendname", equalTo: cuser["fullname"])
query.whereKey("postusername", matchesKey:"whosefriend", inQuery:fQuery)
Is there a way to use multiple "contains(array, value)" functions in an if statement? I have a query that stores in the results in an array. If the results are nil I perform a set of operations. If, however, the array is not nil I'd like to check to see if certain objects appear in it:
var user: PFUser?
override func viewDidLoad() {
super.viewDidLoad()
//get the two players
if let user = user{
var userQuery = PFQuery(className: "Game")
userQuery.whereKey("user1", equalTo: user)
userQuery.whereKey("isActive", equalTo: true)
var userQuery2 = PFQuery(className: "Game")
userQuery2.whereKey("user2", equalTo: user)
userQuery2.whereKey("isActive", equalTo: true)
var currentUserQuery = PFQuery(className: "Game")
currentUserQuery.whereKey("user1", equalTo: PFUser.currentUser())
currentUserQuery.whereKey("isActive", equalTo: true)
var currentUserQuery2 = PFQuery(className: "Game")
currentUserQuery2.whereKey("user2", equalTo: PFUser.currentUser())
currentUserQuery2.whereKey("isActive", equalTo: true)
var query = PFQuery.orQueryWithSubqueries([userQuery, userQuery2, currentUserQuery, currentUserQuery2])
query.findObjectsInBackgroundWithBlock{
(results: [AnyObject]!, error: NSError!) -> Void in
if error == nil{
//if there are no active games, start new game
if results == nil{
//start game code
} else if contains(results, user) as [AnyObject]! && contains(results, PFUser.currentUser()) as [AnyObject]! {
println(results)
}
}
}
}
}
Using the && operator is returning an error on the line: Cannot invoke '&&' with an argument of type '([AnyObject]!,[AnyObject]!)'. Any ideas on how I can test to see if the user and PFUser.current_user() objects are found in the array?
Thanks!
Problem is that you are trying to cast result of contains func call which is Bool in to array of AnyObjects's.
What you need to do instead is just to compare results of contains(results, user) and contains(results, PFUser.currentUser()) functions calls. But it wont compile.
In order to make your compiler happy you need to cast results array to array of [PFUser]
See code:
if let users = results as? [PFUser] {
if contains(users, user) && contains(users, PFUser.currentUser()) {
println(users)
}
}
I want to query the user data based on the profile you are on in my app. As of now my query just gets all the posts not just the user that the profile belongs too.
"Drives" is the class name of the user posts.
post.removeAll(keepCapacity: false)
var findTimelineData:PFQuery = PFQuery(className:"Drives")
findTimelineData.findObjectsInBackgroundWithBlock
{
(objects:[AnyObject]! , error:NSError!) -> Void in
if error == nil
{
self.post = objects.reverse() as [PFObject]
self.table.reloadData()
}
}
post.removeAll(keepCapacity: false)
var findTimelineData:PFQuery = PFQuery(className:"Drives")
//Add the next line
findTimelineData.whereKey("YOUR_COLUMN_NAME_WHERE_THE_USERS_ARE_STORED", equalTo: "THE_NAME_OF_THE_USER")
findTimelineData.findObjectsInBackgroundWithBlock
{
(objects:[AnyObject]! , error:NSError!) -> Void in
if error == nil
{
self.post = objects.reverse() as [PFObject]
self.table.reloadData()
}
}
Or instead you can choose any whereKey... function, listed as here: https://parse.com/docs/ios/api/Classes/PFQuery.html#//api/name/whereKey:equalTo:
UPDATED:
If you query a pointer field, then the whereKey is modified a bit, you have to use relational queries:
let userNameQuery = PFQuery(className: "THE_CLASSNAME_WHERE_THE_USERS_ARE_STORED")
userNameQuery.whereKey("YOUR_COLUMN_NAME_WHERE_THE_NAME_OF_THE_USERS_ARE_STORED", equalTo: "THE_NAME_OF_THE_USER")
let findTimelineData:PFQuery = PFQuery(className:"Drives")
findTimelineData.whereKey("POINTER_COLUMN_OF_USER", matchesQuery: userNameQuery)