2012年11月23日 星期五

Parse.com 超簡單 架Mobile Android Server教學 3.Queries

Basic Queries 基本

ParseQuery query = new ParseQuery("GameScore");
query.whereEqualTo("playerName", "Dan Stemkoski");
query.findInBackground(new FindCallback() {
    public void done(List scoreList, ParseException e) {
        if (e == null) {
            Log.d("score", "Retrieved " + scoreList.size() + " scores");
        } else {
            Log.d("score", "Error: " + e.getMessage());
        }
    }
});
用callback來處理 結果
//ParseException <==有時不見得 失敗 ,它有定義一些奇怪的例外。

query.whereNotEqualTo("playerName", "Michael Yabuti");
query.whereGreaterThan("playerAge", 18);





 setSkip. 跳幾個結果
query.setSkip(10); // skip the first 10 results
排序
// Sorts the results in ascending order by the score field
query.orderByAscending("score");
// Sorts the results in descending order by the score field
query.orderByDescending("score");
可以增加排序規則
// Sorts the results in ascending order by the score field if the previous sort keys are equal.
query.addAscendingOrder("score");
// Sorts the results in descending order by the score field if the previous sort keys are equal.
query.addDescendingOrder("score");
可以設條件式:
// Restricts to wins < 50
query.whereLessThan("wins", 50);
// Restricts to wins <= 50
query.whereLessThanOrEqualTo("wins", 50);
// Restricts to wins > 50
query.whereGreaterThan("wins", 50);
// Restricts to wins >= 50
query.whereGreaterThanOrEqualTo("wins", 50);
可以設多個條件
String[] names = {"Jonathan Walsh", "Dario Wunsch", "Shawn Simon"};
query.whereContainedIn("playerName", Arrays.asList(names));

String[] names = {"Jonathan Walsh", "Dario Wunsch", "Shawn Simon"};
query.whereNotContainedIn("playerName", Arrays.asList(names));
whereDoesNotExist.
// Finds objects that have the score set
query.whereExists("score");
// Finds objects that don't have the score set
query.whereDoesNotExist("score");
可以將ParseQuery 當成參數傳入
ParseQuery teamQuery = new ParseQuery("Team");
teamQuery.whereGreaterThan("winPct", 0.5);
ParseQuery userQuery = ParseUser.getQuery();
userQuery.whereMatchesKeyInQuery("hometown", "city", teamQuery);
userQuery.findInBackground(new FindCallback() {
  void done(List results, ParseException e) {
    // results has the list of users with a hometown team with a winning record
  }
});

還可以用 regular expression 在 whereMatches :
// Finds barbecue sauces that start with a capital letter and a digit.
ParseQuery query = new ParseQuery("BarbecueSauce");
query.whereMatches("name", "^[A-Z]\\d");
query.findInBackground(new FindCallback() {
  public void done(List sauceList, ParseException e) {
    // The sauces could have, for example, name = "A1 Steak Sauce"
  }
});
Parse 使用 Perl-compatible regular expression 格式. Since the regular expression string is escaped by Java before being interpreted by the regular expression engine, be sure that you replace backslashes for the regular expression with double backslashes.
whereMatches has an overload which supports many standard PCRE modifier characters:
i - Case insensitive search
m - Search across multiple lines of input
// Some people type "BBQ", others type "bbq". Consider them the same thing with the i modifier.
// The m modifier helps us find sauces that call themselves "bbq sauce" after the first line of text.
ParseQuery query = new ParseQuery("Sauce");
query.whereMatches("description", "bbq", "im");
query.findInBackground(new FindCallback() {
  public void done(List sauceList, ParseException e) {
    // Sauces that call themselves a "bbq" sauce.
  }
});
There are also several helper functions for standard string operations: substrings, prefixes, and suffixes. Use whereContains to restrict to string values containing a substring:
// Finds barbecue sauces that contain the string "Extra Spicy!".
ParseQuery query = new ParseQuery("BarbecueSauce");
query.whereContains("name", "Extra Spicy!");
Use whereStartsWith to restrict to string values that start with a particular string. Similar to a MySQL LIKE operator, this is indexed so it is efficient for large datasets:
// Finds barbecue sauces that start with "Big Daddy's".
ParseQuery query = new ParseQuery("BarbecueSauce");
query.whereStartsWith("name", "Big Daddy's");

Relational Queries 

There are several ways to issue queries for relational data. If you want to retrieve objects where a field matches a particular ParseObject, you can use whereEqualTo just like for other data types. For example, if each Comment has a Post object in its post field, you can fetch comments for a particular Post:
// Assume ParseObject myPost was previously created.
ParseQuery query = new ParseQuery("Comment");
query.whereEqualTo("post", myPost);
query.findInBackground(new FindCallback() {
  public void done(List commentList, ParseException e) {
    // commentList now has the comments for myPost
  }
});
If you want to retrieve objects where a field contains a ParseObject that matches a different query, you can use whereMatchesQuery. Note that the default limit of 100 and maximum limit of 1000 apply to the inner query as well, so with large data sets you may need to construct queries carefully to get the desired behavior. In order to find comments for posts containing images, you can do:
ParseQuery innerQuery = new ParseQuery("Post");
innerQuery.whereExists("image");
ParseQuery query = new ParseQuery("Comment");
query.whereMatchesQuery("post", innerQuery);
query.findInBackground(new FindCallback() {
  public void done(List commentList, ParseException e) {
    // comments now contains the comments for posts with images.
  }
});
If you want to retrieve objects where a field contains a ParseObject that does not match a different query, you can use whereDoesNotMatchQuery. In order to find comments for posts without images, you can do:
ParseQuery innerQuery = new ParseQuery("Post");
innerQuery.whereExists("image");
ParseQuery query = new ParseQuery("Comment");
query.whereDoesNotMatchQuery("post", innerQuery);
query.findInBackground(new FindCallback() {
  public void done(List commentList, ParseException e) {
    // comments now contains the comments for posts without images.
  }
});
In some situations, you want to return multiple types of related objects in one query. You can do this with the include method. For example, let's say you are retrieving the last ten comments, and you want to retrieve their related posts at the same time:
ParseQuery query = new ParseQuery("Comment");
// Retrieve the most recent ones
query.orderByDescending("createdAt");
// Only retrieve the last ten
query.setLimit(10);
// Include the post data with each comment
query.include("post");
query.findInBackground(new FindCallback() {
  public void done(List commentList, ParseException e) {
    // commentList now contains the last ten comments, and the "post"
    // field has been populated. For example:
    for (ParseObject comment : commentList) {
      // This does not require a network access.
      ParseObject post = comment.getParseObject("post");
      Log.d("post", "retrieved a related post");
    }
  }
});
You can also do multi level includes using dot notation. If you wanted to include the post for a comment and the post's author as well you can do:
query.include("post.author");
You can issue a query with multiple fields included by calling include multiple times. This functionality also works with ParseQuery helpers like getFirst() andgetInBackground().

Caching Queries 暫存收尋結果

It's often useful to cache the result of a query on disk. This lets you show data when the user's device is offline, or when the app has just started and network requests have not yet had time to complete. Parse takes care of automatically flushing the cache when it takes up too much space.
The default query behavior doesn't use the cache, but you can enable caching with setCachePolicy. For example, to try the network and then fall back to cached data if the network is not available:
query.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
query.findInBackground(new FindCallback() {
public void done(List scoreList, ParseException e) {
  if (e == null) {
    // Results were successfully found, looking first on the
    // network and then on disk.
  } else {
    // The network was inaccessible and we have no cached data
    // for this query.
  }
});
Parse provides several different cache policies:
  • IGNORE_CACHE
    The query does not load from the cache or save results to the cache. IGNORE_CACHE is the default cache policy.
  • CACHE_ONLY
    The query only loads from the cache, ignoring the network. If there are no cached results, that causes a ParseException.
  • NETWORK_ONLY
    The query does not load from the cache, but it will save results to the cache.
  • CACHE_ELSE_NETWORK
    The query first tries to load from the cache, but if that fails, it loads results from the network. If neither cache nor network succeed, there is a ParseException.
  • NETWORK_ELSE_CACHE
    The query first tries to load from the network, but if that fails, it loads results from the cache. If neither network nor cache succeed, there is a ParseException.
  • CACHE_THEN_NETWORK
    The query first loads from the cache, then loads from the network. In this case, the FindCallback will actually be called twice - first with the cached results, then with the network results. This cache policy can only be used asynchronously with findInBackground.
If you need to control the cache's behavior, you can use methods provided in ParseQuery to interact with the cache. You can do the following operations on the cache:
  • Check to see if there is a cached result for the query with:
    boolean isInCache = query.hasCachedResult();
  • Remove any cached results for a query with:
    query.clearCachedResult();
  • Remove cached results for all queries with:
    ParseQuery.clearAllCachedResults();
  • Control the maximum age of a cached result with:
    query.setMaxCacheAge(TimeUnit.DAYS.toMillis(1));
Query caching also works with ParseQuery helpers including getFirst() and getInBackground().

Counting Objects

If you just need to count how many objects match a query, but you do not need to retrieve all the objects that match, you can use count instead of find. For example, to count how many games have been played by a particular player:
ParseQuery query = new ParseQuery("GameScore");
query.whereEqualTo("playerName", "Sean Plott");
query.countInBackground(new CountCallback() {
  public void done(int count, ParseException e) {
    if (e == null) {
      // The count request succeeded. Log the count
      Log.d("score", "Sean has played " + count + " games");
    } else {
      // The request failed
    }
  }
});
If you want to block the calling thread, you can also use the synchronous query.count() method.

Compound Queries

If you want to find objects that match one of several queries, you can use ParseQuery.or method to construct a query that is an or of the queries passed in. For instance if you want to find players who either have a lot of wins or a few wins, you can do:
ParseQuery lotsOfWins = new ParseQuery("Player");
lotsOfWins.whereGreaterThan(150);
ParseQuery fewWins = new ParseQuery("Player");
fewWins.whereLessThan(5);
List queries = new ArrayList();
queries.add(lotsOfWins);
queries.add(fewWins);
ParseQuery mainQuery = ParseQuery.or(queries);
mainQuery.findInBackground(new FindCallback() {
  public void done(List results, ParseException e) {
    // results has the list of players that win a lot or haven't won much.
  }
});
You can also add more constraints to the newly constructed ParseQuery which act as an 'and' operator.