Sunday, August 16, 2015

SQL and Parse Query Compared

Here is the object we will work with.


COMMENT

objectIdmembertextcreatedAtupdatedAtACL
VZ9cibW0OerAtRskgtypNicely done!2015-08-07T04:46:43.738Z2015-08-07T04:46:43.738ZPublic Read, rAtRskgtyp
ay9bvW2b1UuYZKeAGinVGood job.2015-08-08T14:15:59.571Z2015-08-08T14:15:59.571ZPublic Read, uYZKeAGinV
ogm7EIAiY9vRtVykXTFnNeeds more work.2015-08-10T15:05:53.314Z2015-08-10T15:05:53.314ZPublic Read, vRtVykXTFn

This is a table in SQL and called a "class" in Parse.


Note

In all of the Parse queries below assume this code replaces the ellipses (...). Because it doesn't change that much I don't want to keep repeating it:

  (rows: [AnyObject]?, error: NSError?) -> Void in
  if error == nil {
      if let rows = rows as? [PFObject] {
          for row in rows {
              println(row)
          }
      }
  } else {
      println(error)
  }



Constraints


SQL

SELECT * 
FROM COMMENT

PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.findObjectsInBackgroundWithBlock {...}



SQL - ORDER BY

SELECT member, text 
FROM COMMENT
ORDER BY 
    updatedAt,
    member,
    createAt DESC,
    objectId DESC


PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.selectKeys(["member", "text"])
query.orderByAscending("updatedAt")
query.addAscendingOrder("member")
query.orderByDescending("createdAt")
query.addDescendingOrder("objectId")
query.findObjectsInBackgroundWithBlock {...}



SQL - TOP, WHERE

SELECT TOP 10 member, text 
FROM COMMENT 
WHERE objectId = "VZ9cibW0Oe"


PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.selectKeys(["member", "text"])
query.limit = 10 // Default: 100, Valid Values: 1 - 1000
query.whereKey("objectId", equalTo: "VZ9cibW0Oe")
query.findObjectsInBackgroundWithBlock {...}


SQL - WHERE, OR

SELECT * 
FROM COMMENT 
WHERE 
    createdAt < "2015-08-08"
    OR
    createdAt > "2015-08-10"


PARSE - SWIFT

var lessThanDate = PFQuery(className:"COMMENT")
lessThanDate.whereKey("createdAt", lessThan: "2015-08-08")

var greaterThanDate = PFQuery(className:"COMMENT")
greaterThanDate.whereKey("createdAt", greaterThan: "2015-08-10")

var query = PFQuery.orQueryWithSubqueries([lessThanDategreaterThanDate])
query.findObjectsInBackgroundWithBlock {...}



SQL - WHERE, AND

SELECT * 
FROM COMMENT 
WHERE 
    createdAt > "2015-08-08"
    AND
    createdAt < "2015-08-09"
    AND
    text IS NOT NULL


PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.whereKey("createdAt", greaterThan: "2015-08-08")
query.whereKey("createdAt", lessThan: "2015-08-09")
query.whereKeyExists("text")
query.findObjectsInBackgroundWithBlock {...}


Query Execution


These are the different ways you can execute a query besides using findObjectsInBackgroundWithBlock.

SQL - TOP 1

SELECT TOP 1 * 
FROM COMMENT

PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.getFirstObjectInBackgroundWithBlock {...}

// Alternative (Does not happen in background):
if let row: PFObject = query.getFirstObject() {
    // A result was returned.
}


SQL - COUNT

SELECT COUNT(member
FROM COMMENT 
WHERE member = "VZ9cibW0Oe"


PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.whereKey("member", equalTo: "VZ9cibW0Oe")
query.countObjectsInBackgroundWithBlock  {
  (count: Int, error: NSError?) -> Void in
  if error == nil {
    println("Member commented \(count) times.")
  }
}


Multiple Tables


Let's step things up by showing you how to query data from multiple tables. Parse doesn't have JOINs so how you approach your solution might look a little different.

Let's include the Member table/class now.

MEMBER

objectIdrealnameusernamedeletedAtcreatedAtupdatedAtACL
VZ9cibW0OeJohn DoeJohnDoe2015-08-07T04:46:43.738Z2015-08-07T04:46:43.738ZPublic Read, VZ9cibW0Oe
ay9bvW2b1UJane SmithJaneSmith2015-09-01T10:15:14.571Z2015-08-08T14:15:59.571Z2015-08-08T14:15:59.571ZPublic Read, ay9bvW2b1U
ogm7EIAiY9Bill FordBillFord2015-08-10T15:05:53.314Z2015-08-08T15:05:53.314ZPublic Read, ogm7EIAiY9


SQL - INNER JOIN, WHERE FROM ONE TABLE

SELECT 
    MEMBER.realname, 
    COMMENT.text
FROM 
    COMMENT
    INNER JOIN MEMBER ON COMMENT.member = MEMBER.objectId
WHERE
    COMMENT.objectId = "ogm7EIAiY9"

PARSE - SWIFT

var query = PFQuery(className:"COMMENT")
query.selectKeys(["member", "text"]) // Note, you cannot access fields from the MEMBER table in the selectKeys, just fields from COMMENT.

// includeKey Tips
// Include the whole MEMBER row/object.
// This is the field name from COMMENT, not the table name.
// You must also make sure the field you are using "includeKey" is also in the "selectKeys" array.
query.includeKey("member")

query.whereKey("objectId", equalTo: "ogm7EIAiY9")
query.findObjectsInBackgroundWithBlock {
    (rows: [AnyObject]?, error: NSError?) -> Void in
    if error == nil {
        if let rows = rows as? [PFObject] {
            for row in rows {
                let text = row["text"] as! String
                if let member = row["member"] as? PFObject {
                    let username = member["username"] as! String
                }
            }
        }
    } else {
        println(error)
    }
}



SQL - INNER JOIN, WHERE FROM TWO TABLES, IS [NOT] NULL

SELECT 
    MEMBER.realname, 
    COMMENT.text
FROM 
    COMMENT
    INNER JOIN MEMBER ON COMMENT.member = MEMBER.objectId
WHERE
    COMMENT.text IS NOT NULL
    AND
    MEMBER.deletedAt IS NULL

PARSE - SWIFT

var memberQuery = PFQuery(className:"MEMBER")
memberQuery.whereKeyDoesNotExist("deletedAt") // IS NULL

var commentQuery = PFQuery(className:"COMMENT")
commentQuery.selectKeys(["member", "text"])
commentQuery.includeKey("member")
commentQuery.whereKeyExists("text") // IS NOT NULL

// The first param is the field from COMMENT that represents the MEMBER object.
commentQuery.whereKey("member", matchesQuery: memberQuery)

commentQuery.findObjectsInBackgroundWithBlock {
    (rows: [AnyObject]?, error: NSError?) -> Void in
    if error == nil {
        if let rows = rows as? [PFObject] {
            for row in rows {
                let text = row["text"] as! String
                if let member = row["member"] as? PFObject {
                    let username = member["realname"] as! String
                }
            }
        }
    } else {
        println(error)
    }
}








For more info on doing queries in Parse, go here.

Friday, August 7, 2015

Push Notifications to a Geographical Area

JAVA

ParseGeoPoint weberUniversity = new ParseGeoPoint();
weberUniversity.latitude = 41.192127;
weberUniversity.longitude = -111.944816;

// Find users near a given location
ParseQuery userQuery = ParseUser.getQuery();
userQuery.whereWithinMiles("location", stadiumLocation, 1.0)

// Find devices associated with these users
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereMatchesQuery("user", userQuery);

// Send push notification to query
ParsePush push = new ParsePush();
push.setQuery(pushQuery); // Set our Installation query
push.setMessage("Free hotdogs at the Parse concession stand!");
push.sendInBackground();

SWIFT

PFGeoPoint weberUniversity = new PFGeoPoint()
weberUniversity.latitude = 41.192127
weberUniversity.longitude = -111.944816

// Find users near a given location
let userQuery = PFUser.query()
userQuery.whereKey("location", nearGeoPoint: weberUniversity, withinMiles: 1)

// Find devices associated with these users
let pushQuery = PFInstallation.query()
pushQuery.whereKey("user", matchesQuery: userQuery)

// Send push notification to query
let push = PFPush()
push.setQuery(pushQuery) // Set our Installation query
push.setMessage("New contest starting soon! Stay tuned.")
push.sendPushInBackground()

Push Notifications From A Query

JAVA

ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereEqualTo("State", "UT");

ParsePush push = new ParsePush();
push.setQuery(pushQuery);

// This next property is for Android and Windows Phone 8
push.title = "Sale in Utah";
push.setMessage("There is a sale in Utah today!");
push.sendInBackground();

SWIFT

let pushQuery = PFInstallation.query()
pushQuery.whereKey("State", equalTo: "UT")

let push = PFPush()
push.setQuery(pushQuery)

// The next properties are iOS only
let data = [
  "alert" : "There is a sale in Utah today!",
  "badge" : "Increment",
  "sounds" : "cheering.caf"
]
push.setData(data)
push.setMessage("There is a sale in Utah today!")
push.sendPushInBackground()

Push Notifications To Channel(s)

JAVA

ParsePush push = new ParsePush();
push.setChannel("AllUsers");
push.setMessage("The app will be down for maintenance at midnight EST for two hours.");
push.sendInBackground();

Multiple Channels

LinkedList<String> channels = new LinkedList<String>();
channels.add("PaidSubscribers");
channels.add("FreeSubscribers");

ParsePush push = new ParsePush();

// Be sure to use the plural 'setChannels'.
push.setChannels(channels); 
push.setMessage("There is a sale today in the store!");
push.sendInBackground();

SWIFT

let push = PFPush()
push.setChannel("AllUsers")
push.setMessage("The app will be down for maintenance at midnight EST for two hours.")
push.sendPushInBackground()


Multiple Channels


let channels = [ "PaidSubscribers", "FreeSubscribers" ];
let push = PFPush()

// Be sure to use the plural 'setChannels'.
push.setChannels(channels)
push.setMessage("There is a sale today in the store!")

push.sendPushInBackground()

Thursday, August 6, 2015

Give a User Rights to Edit Parse Table Row (Class)

Basically if you save the user with the record then they have write access to that record.


JAVA

ParseObject myParseTable = new ParseObject("MyParseTable");
myParseTable.put("ID", "1");
myParseTable.put("Message", "I can now edit this message.");
myParseTable.put("author", ParseUser.getCurrentUser());

myParseTable.saveInBackground();

SWIFT

var myParseTable = PFObject(className:"MyParseTable")
myParseTable["Message"] = "1"
myParseTable["Message"] = "I can now edit this message."
myParseTable.ACL = PFACL.ACLWithUser(PFUser.currentUser())

myParseTable.saveInBackground()

Logging In a User

JAVA

ParseUser.logInInBackground("johndoe", "p@ssw0rd", new LogInCallback() {
    public void done(ParseUser user, ParseException e) {
        if (user != null) {
            // User has logged in successfully.
        } else {
            // Error! Access the "e" variable to find out what.
        }
    }
});

SWIFT

PFUser.logInWithUsernameInBackground("johndoe", password:"p@ssw0rd") {
  (user: PFUser?, error: NSError?) -> Void in
  if user != nil {
    // Do stuff after successful login.
  } else {
    // The login failed. Check "error" variable to see why.
  }

}

Creating a New User For Your App

JAVA

ParseUser user = new ParseUser();
user.setUsername("johndoe");
user.setPassword("p@ssw0rd");
user.setEmail("johndoe@gmail.com");
user.signUpInBackground();

SWIFT

var user = PFUser()
user.username = "johndoe"
user.password = "p@ssw0rd"
user.email = "johndoe@gmail.com"
// other fields can be set just like with PFObject
user["phone"] = "415-392-0202"

user.signUpInBackgroundWithBlock {
  (succeeded: Bool, error: NSError?) -> Void in
  if let error = error {
    let errorString = error.userInfo?["error"] as? NSString
    // Show the errorString somewhere and let the user try again.
  } else {
    // Hooray! Let them use the app now.
  }

}

Save a File to a Parse Table

JAVA

// Prepare File
byte[] photoBytes = myPhotoObject.toByteArray();
ParseFile photo = new ParseFile("myPicture.jpg", photoBytes);
photo.saveInBackground();

// Now save to Parse Table
ParseObject myParseTable = new ParseObject("MyParseTable");
myParseTable.put("ID", "1");
myParseTable.put("Photo", photo);
myParseTable.saveInBackground();


SWIFT

// Prepare File
let imageData = UIImagePNGRepresentation(image)
let photo= PFFile(name:"myPicture.jpg", data:imageData)

// Now save to Parse Table
var myParseTable = PFObject(className:"MyParseTable")
myParseTable["ID"] = "1"
myParseTable["Photo"] = photo

myParseTable.saveInBackground()

Query Data from a Parse Table

JAVA

ParseQuery<ParseObject> query = ParseQuery.getQuery("MyParseTable");

query.whereEqualTo("ID", "1");
query.findInBackground(new FindCallback<ParseObject>() {
    public void done(List<ParseObject> results, ParseException e) {
        if (e == null) {
            // You have all the results in the "results" variable.
        } else {
            // There was an exception. Check the "e" variable.
        }
    }
}


SWIFT

var query = PFQuery(className:"MyParseTable")

query.getObjectInBackgroundWithId("1") {
  (results: PFObject?, error: NSError?) -> Void in
  if error == nil && results!= nil {
    println(results)
  } else {
    println(error)
  }
}

Inserting Data to a Table (Class) in Parse

JAVA

ParseObject myParseTable= new ParseObject("MyParseTable");

myParseTable.put("ID", "1");
myParseTable.put("Name", "Mark");
myParseTable.put("Message", "Hello World!");

myParseTable.saveInBackground();


SWIFT

var myParseTable = PFObject(className:"myParseTable")

myParseTable["ID"] = "1"
myParseTable["Name"] = "Mark"
myParseTable["Message"] = "Hello World!"

myParseTable.saveInBackgroundWithBlock {
  (success: Bool, error: NSError?) -> Void in
  if (success) {
    // The object has been saved.
  } else {
    // There was a problem, check error.description
  }
}