查询

我们已经知道了Parse.Query是如何使用get从Parse云端查询一个对象的,下面还有许多其他方法,比如你可以一次查询多个对象,可以在一个查询上限制条件等。

基本查询

很多时候,get可能满足不了你的欲望。

所以,Parse.Query提供了其他的方法,可以让你查询一批对象,而不是一个对象。

最常用的方法是始创建一个Parse.Query,为其设置查询条件,然后使用find方法查询匹配的对象列表。比如,要查询一个玩家的playerName的得分,我们使用equalTo方法来设定“等于”查询条件:

  1. var GameScore = Parse.Object.extend("GameScore");
  2. var query = new Parse.Query(GameScore);
  3. query.equalTo("playerName", "Dan Stemkoski");
  4. query.find({
  5. success: function(results) {
  6. alert("Successfully retrieved " + results.length + " scores.");
  7. // Do something with the returned Parse.Object values
  8. for (var i = 0; i < results.length; i++) {
  9. var object = results[i];
  10. alert(object.id + ' - ' + object.get('playerName'));
  11. }
  12. },
  13. error: function(error) {
  14. alert("Error: " + error.code + " " + error.message);
  15. }
  16. });

查询条件

下面有几个方法可以约束Parse.Query的查询结果,比如你可以用notEqualTo方法,传入键值对来筛选结果:

  1. query.notEqualTo("playerName", "Michael Yabuti");

你可以给定多个约束条件,只有条件匹配的对象会被作为查询结果返回。在口语中,这和“且”的条件限制相似:

  1. query.notEqualTo("playerName", "Michael Yabuti");
  2. query.greaterThan("playerAge", 18);

你可以限定查询结果的返回数量,默认情况下,返回数量是100:

  1. query.limit(10); // limit to at most 10 results

如果你只想查询一个结果,可以用更方便的first方法替代find方法:

  1. var GameScore = Parse.Object.extend("GameScore");
  2. var query = new Parse.Query(GameScore);
  3. query.equalTo("playerEmail", "dstemkoski@example.com");
  4. query.first({
  5. success: function(object) {
  6. // Successfully retrieved the object.
  7. },
  8. error: function(error) {
  9. alert("Error: " + error.code + " " + error.message);
  10. }
  11. });

你可以通过设置skip来跳过x个查询结果,这在分页功能中很有:

  1. query.skip(10); // skip the first 10 results

对于可排序的字段类型,如string、number、date,你可以指定字段类型的排序,控制返回结果的排序:

  1. // Sorts the results in ascending order by the score field
  2. query.ascending("score");
  3. // Sorts the results in descending order by the score field
  4. query.descending("score");

对于可排序类型,你还可以在查询中使用比较:

  1. //wins < 50
  2. query.lessThan("wins", 50);
  3. // wins <= 50
  4. query.lessThanOrEqualTo("wins", 50);
  5. // wins > 50
  6. query.greaterThan("wins", 50);
  7. // wins >= 50
  8. query.greaterThanOrEqualTo("wins", 50);

如果你想查询与数组中任意值匹配的对象,可以使用containedIn方法,并提供一个可接受值的数组。这样可以一个请求完成多个请求的功能。比如,你想查询数组中玩家的分数结果:

  1. // Finds scores from any of Jonathan, Dario, or Shawn
  2. query.containedIn("playerName",
  3. ["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);

如果你想查询和数组中任意值都不匹配的对象,你可以使用notContainedIn,并给定一个排除值的数组。比如,你想查询不在数组中的玩家分数:

  1. // Finds scores from anyone who is neither Jonathan, Dario, nor Shawn
  2. query.notContainedIn("playerName",
  3. ["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);

如果你想查询指定字段已被设置的对象,你可以使用exists;反之,如果想查询未被设置的对象,你可以使用doesNotExist

  1. // Finds objects that have the score set
  2. query.exists("score");
  3. // Finds objects that don't have the score set
  4. query.doesNotExist("score");

你可以使用meachesKeyInQuery方法查询对象,对象中的某个键值是和另一个请求返回的一组结果中的键值匹配的。比如,如果你有一个包含了运动队的类,并且你保存了用户的老家信息在user类中,你现在要查询获胜队伍的成员家乡信息,你可以这样请求:

  1. var Team = Parse.Object.extend("Team");
  2. var teamQuery = new Parse.Query(Team);
  3. teamQuery.greaterThan("winPct", 0.5);
  4. var userQuery = new Parse.Query(Parse.User);
  5. userQuery.matchesKeyInQuery("hometown", "city", teamQuery);
  6. userQuery.find({
  7. success: function(results) {
  8. // results has the list of users with a hometown team with a winning record
  9. }
  10. });

反之,如果你要查询,对象中的某个键值是和另一个请求返回的一组结果中的键值是不匹配的,用doesNotMatchKeyInQuery。比如,查询战败队成员的家乡信息:

  1. var losingUserQuery = new Parse.Query(Parse.User);
  2. losingUserQuery.doesNotMatchKeyInQuery("hometown", "city", teamQuery);
  3. losingUserQuery.find({
  4. success: function(results) {
  5. // results has the list of users with a hometown team with a losing record
  6. }
  7. });

你可以使用select限定返回的字段。如果你想查询只包含了scoreplayerName字段的数据记录(还有指定的内置字段objectId、createdAt和updatedAt):

  1. var GameScore = Parse.Object.extend("GameScore");
  2. var query = new Parse.Query(GameScore);
  3. query.select("score", "playerName");
  4. query.find().then(function(results) {
  5. // each of results will only have the selected fields available.
  6. });

剩下的字段你可以使用fetch方法,在需要的时候拉取:

  1. query.first().then(function(result) {
  2. // only the selected fields of the object will now be available here.
  3. return result.fetch();
  4. }).then(function(result) {
  5. // all fields of the object will now be available here.
  6. });

比较查询 {#hash858517260}

逻辑操作 Query 方法
等于 equalTo
不等于 notEqualTo
大于 greaterThan
大于等于 greaterThanOrEqualTo
小于 lessThan
小于等于 lessThanOrEqualTo

数组查询

对于数组类型的字段,你可以查询到arrayKey包含了2的对象:

  1. // Find objects where the array in arrayKey contains 2.
  2. query.equalTo("arrayKey", 2);

你也可以这样查询到键值包含了2、3、4的的对象:

  1. // Find objects where the array in arrayKey contains all of the elements 2, 3, and 4.
  2. query.containsAll("arrayKey", [2, 3, 4]);

字符串查询

如果你想实现一个通用的搜索功能,我们推荐你看看这篇博文:Implementing Scalable Search on a NoSQL Backend

我们可以使用startWith限制特定开头的字符串值,类似与MySQL中的LIKE操作。这是索引过的,所以在大数据集中也有效:

  1. // Finds barbecue sauces that start with "Big Daddy's".
  2. var query = new Parse.Query(BarbecueSauce);
  3. query.startsWith("name", "Big Daddy's");

上面的例子将会查询到name以“Big Daddy’s”开头的对象,”Big Daddy’s” 和 “Big Daddy’s BBQ”都会被匹配到,但是”big daddys’s”或者”BBQ Sauce:Big Daddy’s”不会。

使用正则查询是非常耗费性能的,尤其是超过10万条数据时。Parse限制了给定时间里特定应用可以执行多少次这样的查询。


关系查询

有几种方法可以查询关系型的数据。如果你想查询某字段为某个对象的话,可以直接像查询其他类型一样使用equalTo。比如每个Comment都有一个post字段指向Post,你可以这样查询特定Post的评论:

  1. // Assume Parse.Object myPost was previously created.
  2. var query = new Parse.Query(Comment);
  3. query.equalTo("post", myPost);
  4. query.find({
  5. success: function(comments) {
  6. // comments now contains the comments for myPost
  7. }
  8. });

如果你想查询某字段包含一个和另一个查询匹配的对象,你可以使用matchesQuery。为了查询包含图片的文章的评论,你可以这样:

  1. var Post = Parse.Object.extend("Post");
  2. var Comment = Parse.Object.extend("Comment");
  3. var innerQuery = new Parse.Query(Post);
  4. innerQuery.exists("image");
  5. var query = new Parse.Query(Comment);
  6. query.matchesQuery("post", innerQuery);
  7. query.find({
  8. success: function(comments) {
  9. // comments now contains the comments for posts with images.
  10. }
  11. });

反之,你想查询某字段不包含和另一个查询匹配的对象,你可以使用doesNotMatchesQuery

  1. var Post = Parse.Object.extend("Post");
  2. var Comment = Parse.Object.extend("Comment");
  3. var innerQuery = new Parse.Query(Post);
  4. innerQuery.exists("image");
  5. var query = new Parse.Query(Comment);
  6. query.doesNotMatchQuery("post", innerQuery);
  7. query.find({
  8. success: function(comments) {
  9. // comments now contains the comments for posts without images.
  10. }
  11. });

你也可以通过objectId来查询关联对象:

  1. var post = new Post();
  2. post.id = "1zEcyElZ80";
  3. query.equalTo("post", post);

在某些情况下,你想要在一次查询中返回多个类型的关联对象,那么你可以使用include方法。比如说你想查询最新的10条评论,并同时查询到关联的文章:

  1. var query = new Parse.Query(Comment);
  2. // Retrieve the most recent ones
  3. query.descending("createdAt");
  4. // Only retrieve the last ten
  5. query.limit(10);
  6. // 评论对象同时包含文章对象
  7. query.include("post");
  8. query.find({
  9. success: function(comments) {
  10. // Comments now contains the last ten comments, and the "post" field
  11. // has been populated. For example:
  12. for (var i = 0; i < comments.length; i++) {
  13. // This does not require a network access.
  14. var post = comments[i].get("post");
  15. }
  16. }
  17. });

你也可以使用post.author的形式嵌套查询,如果你想查询包含了文章和文章作者的评论,你可以这样:

  1. query.include(["post.author"]);

你可以多次调用include,发起一个包含了多个字段的请求,这个功能在Parse.Query的其他查询方法中也有效,比如firstget


统计查询

如果你只是想知道有多少个匹配的对象,但不需要拿到对象的详细信息,你可以使用count方法替代find方法。比如,你想知道特定玩家玩了多少个游戏:

  1. var GameScore = Parse.Object.extend("GameScore");
  2. var query = new Parse.Query(GameScore);
  3. query.equalTo("playerName", "Sean Plott");
  4. query.count({
  5. success: function(count) {
  6. // The count request succeeded. Show the count
  7. alert("Sean has played " + count + " games");
  8. },
  9. error: function(error) {
  10. // The request failed
  11. }
  12. });

组合查询

更复杂的查询情况下,你可能需要用到组合查询。一个组合查询是多个子查询的组合(如”and或”or”)。

需要注意的是,我们不支持在组合查询的子查询中使用GeoPint或者非过滤类型的约束条件。

或查询

如果你想查询多个请求中符合其中一个即可的数据,你可以使用Parse.Query.or方法构建一个由传入的子查询组成的或查询。比如你想查询胜利次数在指定范围的玩家,你可以这样:

  1. var lotsOfWins = new Parse.Query("Player");
  2. lotsOfWins.greaterThan("wins", 150);
  3. var fewWins = new Parse.Query("Player");
  4. fewWins.lessThan("wins", 5);
  5. var mainQuery = Parse.Query.or(lotsOfWins, fewWins);
  6. mainQuery.find()
  7. .then(function(results) {
  8. // results contains a list of players that either have won a lot of games or won only a few games.
  9. })
  10. .catch(function(error) {
  11. // There was an error.
  12. });

与查询

如果你想查询和所有条件都符合的数据,通常只需要一次请求。你可以添加额外的条件,它实际上就是与查询:

  1. var query = new Parse.Query("User");
  2. query.greaterThan("age", 18);
  3. query.greaterThan("friends", 0);
  4. query.find()
  5. .then(function(results) {
  6. // results contains a list of users both older than 18 and having friends.
  7. })
  8. .catch(function(error) {
  9. // There was an error.
  10. });

但如果这个世界真的有这么简单那就好了。有时你可能需要用到与组合查询,Parse.Query.and方法可以构建一个由传入的子程序组成的与查询。比如你想查询用户年龄为16或者18,并且ta的好友少于两人的用户,你可以这样:

  1. var age16Query = new Parse.Query("User");
  2. age16Query.equalTo("age", 16);
  3. var age18Query = new Parse.Query("User");
  4. age18Query.equalTo("age", 18);
  5. var friends0Query = new Parse.Query("User");
  6. friends0Query.equalTo("friends", 0);
  7. var friends2Query = new Parse.Query("User");
  8. friends2Query.greaterThan("friends", 2);
  9. var mainQuery = Parse.Query.and(
  10. Parse.Query.or(age16Query, age18Query),
  11. Parse.Query.or(friends0Query, friends2Query)
  12. );
  13. mainQuery.find()
  14. .then(function(results) {
  15. // results contains a list of users in the age of 16 or 18 who have either no friends or at least 2 friends
  16. // results: (age 16 or 18) and (0 or >2 friends)
  17. })
  18. .catch(function(error) {
  19. // There was an error.
  20. });

#