简体   繁体   中英

Parse via Swift with Complex Queries

Im having some difficulty with creating complex queries in Parse. What I'm looking to achieve is searching the _Users class and not returning myself as a result and if an Invite already exists in the Invites class, show Pending text rather than Add Button and if both myself and user have already accepted invite, dont show them at all.

I've achieved some of it but I'm not sure i'm doing it the most efficient way. For instance, I first query the _User class and find any users that match the search terms, then loop through and if the objectId == currentUser().objectId, skip that record. Then I run another query in that loop on each record to see if there are any pending invites, if so, i set a flag to true for Pending however i've done that search not in the background because i was having isses with the first query block finishing before the second and my flag not getting set first. So would I then do a third query to see if the field is accepted? Or is there a way to make this all one big query? My code is below for the searching:

func performSearchForText(text: String, completion: SearchComplete) { state = .Loading

    // Query Parse

    var containsDisplayName = PFQuery(className:"_User")
    containsDisplayName.whereKey("displayName", containsString: text)

    var containsUsername = PFQuery(className: "_User")
    containsUsername.whereKey("username", containsString: text)

    var query = PFQuery.orQueryWithSubqueries([containsUsername, containsDisplayName])
    query.findObjectsInBackgroundWithBlock {
        (results: [AnyObject]?, error: NSError?) -> Void in
        //self.state = .NotSearchedYet
        var success = false

        if error == nil {
            // Found results
            // Set Result state to either Results or NoResults
            if let results = results {
                //println(results)
                if results.count == 0 {
                    self.state = .NoResults
                } else {
                    // Read Results into UserSearchResult Array
                    // Dont show self in results
                    // If user has already accepted a request, dont show
                    // If they have already invited, show Pending instead of button

                    var userSearchResults = [UserSearchResult]()
                    var searchResult = UserSearchResult()

                    for result in results {
                        if result.objectId != PFUser.currentUser()?.objectId {
                            // Query invites table to see if they already are accepted with user
                            // or if a pending invite exists
                            // Set invite or accepted respectively
                            var invitedQuery = PFQuery(className: "Invites")
                            invitedQuery.whereKey("pending", equalTo: true)
                            invitedQuery.whereKey("inviteToUser", equalTo: result.objectId!!)
                            var invitedQueryResults = invitedQuery.findObjects()
                            if invitedQueryResults?.count > 0 {
                                self.pendingInvite = true
                            }

                            searchResult.displayName = result["displayName"] as! String
                            searchResult.emailAddress = result["username"] as! String
                            searchResult.inviteUserID = result.objectId!!
                            searchResult.invited = self.pendingInvite
                            searchResult.accepted = false
                            userSearchResults.append(searchResult)
                        }
                    }

                    if userSearchResults.count > 0 {
                        self.state = .Results(userSearchResults)
                    } else {
                        self.state = .NoResults
                    }

                }
                    success = true
                }

            dispatch_async(dispatch_get_main_queue()) {
                UIApplication.sharedApplication().networkActivityIndicatorVisible = false
                completion(success)
            }
        } else {
            // Error, print it
            println(error)
        }
    }
}

Unless there's a lot more to your invites table, I'd suggest removing it and adding an "invitePending" field to your user table.

Then you can just further refine your other queries by using wherekey("invitePending", equalTo: true).

Additionally, you can do something like this at the start so you don't have to check for currentUser in the query completion block:

containsDisplayName.whereKey("objectId", notEqualTo: PFUser.currentUser()!.objectId!)

But you definitely don't need the invites table if it isn't storing lots of other info. If you have to keep it as a separate table, using a pointer (for 1 to 1) or a PFRelation (for 1 to many) would save you the headache of that inner query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM