查询
我们已经看到了Parse.Query如何使用get从Parse中检索一个Parse.Object。Parse.Query还有许多其他方法来检索数据——您可以一次检索多个对象、在待检索对象上添加条件等等。
1.基本查询
在许多情况下,get还不够强大到足以明确要检索的对象。Parse.Query提供了不同的方式来检索一组对象列表,而不仅仅是单个对象。
一般模式是创建一个Parse.Query,放置条件,然后使用find检索一组匹配的Parse.Object。例如,要检索具有特定playerName的分数,可使用equalTo方法来约束一个键的值。
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", "Dan Stemkoski");
query.find({
success: function(results) {
alert("Successfully retrieved " + results.length + " scores.");
// Do something with the returned Parse.Object values
for (var i = 0; i < results.length; i++) {
var object = results[i];
alert(object.id + ' - ' + object.get('playerName'));
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
2.查询约束
有几种方法来为Parse.Query找到的对象提供约束条件。您可以使用notEqualTo过滤出具有特定键值对的对象:
query.notEqualTo("playerName", "Michael Yabuti");
您可以给出多个约束,只有匹配所有约束的对象才会出现在结果中。换句话说,它就像一个AND约束条件。
query.notEqualTo("playerName", "Michael Yabuti");
query.greaterThan("playerAge", 18);
您可以通过设置limit限制结果数量。默认情况下,返回结果被限制为100。在旧的Parse托管后端中,最大约束为1,000,但是Parse Server删除了该约束:
query.limit(10); // limit to at most 10 results
如果你只想要一个结果,更方便的替代方法是使用first而不是使用find。
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerEmail", "dstemkoski@example.com");
query.first({
success: function(object) {
// Successfully retrieved the object.
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
您可以通过设置skip跳过第一个结果。在旧的Parse托管后端中,最大跳过值为10,000,但Parse Server删除了该约束。这对分页有用:
query.skip(10); // skip the first 10 results
对于可排序类型(如数字和字符串),您可以控制返回结果的顺序:
// Sorts the results in ascending order by the score field
query.ascending("score");
// Sorts the results in descending order by the score field
query.descending("score");
对于可排序类型,您还可以在查询中使用比较:
// Restricts to wins < 50
query.lessThan("wins", 50);
// Restricts to wins <= 50
query.lessThanOrEqualTo("wins", 50);
// Restricts to wins > 50
query.greaterThan("wins", 50);
// Restricts to wins >= 50
query.greaterThanOrEqualTo("wins", 50);
如果要检索匹配值列表中任何值的对象,可以使用containedIn,并给定一组可接受的值。这通常用于使用单个查询替换多个查询。例如,如果您想要检索特定列表中所有玩家的分数:
// Finds scores from any of Jonathan, Dario, or Shawn
query.containedIn("playerName",
["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);
如果要检索与几个值都不匹配的对象,可使用notContainedIn,并给定一组可接受的值。例如,如果您要检索除列表中以外的玩家的分数:
// Finds scores from anyone who is neither Jonathan, Dario, nor Shawn
query.notContainedIn("playerName",
["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);
如果要检索具有特定键集的对象,可以使用exists。相反,如果要检索没有特定键集的对象,则可以使用doesNotExist。
// Finds objects that have the score set
query.exists("score");
// Finds objects that don't have the score set
query.doesNotExist("score");
您可以使用matchesKeyInQuery方法来获取这样的对象:查询中的某个键与另一个查询产生的一组对象中某个键的值相匹配。例如,如果您有一个包含运动队的类(译者注:包含“city”字段),且用户类中存储有用户的家乡(译者注:包含“hometown”字段),则可以发起一个查询来查找其家乡运动队具有获胜记录的用户列表。查询将如下所示:
var Team = Parse.Object.extend("Team");
var teamQuery = new Parse.Query(Team);
teamQuery.greaterThan("winPct", 0.5);
var userQuery = new Parse.Query(Parse.User);
userQuery.matchesKeyInQuery("hometown", "city", teamQuery);
userQuery.find({
success: function(results) {
// results has the list of users with a hometown team with a winning record
}
});
相反的,要获取其中某个键与另一个查询产生的一组对象中某个键的值不匹配的对象,请使用doesNotMatchKeyInQuery。例如,要找到家乡团队有失败记录的用户:
var losingUserQuery = new Parse.Query(Parse.User);
losingUserQuery.doesNotMatchKeyInQuery("hometown", "city", teamQuery);
losingUserQuery.find({
success: function(results) {
// results has the list of users with a hometown team with a losing record
}
});
您可以调用包含一组键的select来限定返回的字段。要检索仅包含score和playerName字段的文档(当然还包括如objectId、createdAt和updatedAt的特别内置字段):
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.select("score", "playerName");
query.find().then(function(results) {
// each of results will only have the selected fields available.
});
剩余字段可以稍后通过在返回的对象上调用fetch来获取:
query.first().then(function(result) {
// only the selected fields of the object will now be available here.
return result.fetch();
}).then(function(result) {
// all fields of the object will now be available here.
});
3.查询数组值
对于具有数组类型的键,可以通过以下方式找到键的数组值为2的对象:
// Find objects where the array in arrayKey contains 2.
query.equalTo("arrayKey", 2);
您还可以查找键的数组值包含2,3和4的对象:
// Find objects where the array in arrayKey contains all of the elements 2, 3, and 4.
query.containsAll("arrayKey", [2, 3, 4]);
4.查询字符串值
如果您正在尝试实现通用的搜索功能,我们建议您查看此博文:在NoSQL后端实现可扩展搜索。
可使用startsWith来检索以特定字符串开头的字符串值。与MySQL LIKE运算符类似,它是有索引的,因此对于大型数据集它也很高效:
// Finds barbecue sauces that start with "Big Daddy's".
var query = new Parse.Query(BarbecueSauce);
query.startsWith("name", "Big Daddy's");
上述示例将匹配BarbecueSauce中“name”键中的值以“Big Daddy's”开头的任何对象。例如,“Big Daddy’s”和“Big Daddy’s BBQ”都会匹配,但是“big daddy’s”和“BBQ Sauce: Big Daddy’s”不会。
具有正则表达式约束的查询代价非常昂贵,特别是对于超过100,000条记录的类。Parse限制了在给定时间内应用程序运行这样操作的次数。
5.关系型查询
有几种方式来发起关系数据查询。如果要检索与特定Parse.Object字段匹配的对象,可以像其他数据类型一样使用equalTo。例如,如果每个Comment的post字段中都有一个Post对象,则可这样获取针对特定Post的comments:
// Assume Parse.Object myPost was previously created.
var query = new Parse.Query(Comment);
query.equalTo("post", myPost);
query.find({
success: function(comments) {
// comments now contains the comments for myPost
}
});
如果要检索对象的某个字段包含从别的查询中匹配的对象,可以使用matchesQuery。为了找到包含图像的帖子的评论,你可以这样做:
var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");
var innerQuery = new Parse.Query(Post);
innerQuery.exists("image");
var query = new Parse.Query(Comment);
query.matchesQuery("post", innerQuery);
query.find({
success: function(comments) {
// comments now contains the comments for posts with images.
}
});
如果要检索对象的某个字段包含从别的查询中不匹配的对象,可以使用doesNotMatchQuery。为了找到没有图像的帖子的评论,你可以这样:
var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");
var innerQuery = new Parse.Query(Post);
innerQuery.exists("image");
var query = new Parse.Query(Comment);
query.doesNotMatchQuery("post", innerQuery);
query.find({
success: function(comments) {
// comments now contains the comments for posts without images.
}
});
您还可以通过objectId进行关系查询:
var post = new Post();
post.id = "1zEcyElZ80";
query.equalTo("post", post);
在某些情况下,您希望在一个查询中返回多种类型的相关对象,则可以使用include方法。例如,假设您正在检索最近十条评论,并同步检索出与之相关的帖子:
var query = new Parse.Query(Comment);
// Retrieve the most recent ones
query.descending("createdAt");
// Only retrieve the last ten
query.limit(10);
// Include the post data with each comment
query.include("post");
query.find({
success: function(comments) {
// Comments now contains the last ten comments, and the "post" field
// has been populated. For example:
for (var i = 0; i < comments.length; i++) {
// This does not require a network access.
var post = comments[i].get("post");
}
}
});
您还可以使用点标记进行多级包含。如果你想包括某个评论有关的帖子和帖子的作者,你可以做:
query.include(["post.author"]);
您可以通过多次调用include以在查询中包含多个字段。此功能也适用于Parse.Query助手,如first和get。
6.计数对象
注意:在旧的Parse托管后端中,计数查询的频度限制为每分钟最多请求160次。而且当类中超过1000个对象时还会返回不准确的结果。不过,Parse Server已经删除了这两个限制,在对象超过1000时计数也工作良好。
如果您只需要计算与查询匹配的对象数量,而不需要检索出所有匹配的对象,则可以使用count而不是find。例如,计算特定玩家玩过的游戏数量:
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", "Sean Plott");
query.count({
success: function(count) {
// The count request succeeded. Show the count
alert("Sean has played " + count + " games");
},
error: function(error) {
// The request failed
}
});
7.复合查询
如果要查找的对象只匹配几个查询条件中的一个,可以使用Parse.Query.or方法,该方法传入的查询条件之间是OR的关系。例如,如果您想要查找有很多胜利或少数胜利的玩家, 你可以这样:
var lotsOfWins = new Parse.Query("Player");
lotsOfWins.greaterThan("wins", 150);
var fewWins = new Parse.Query("Player");
fewWins.lessThan("wins", 5);
var mainQuery = Parse.Query.or(lotsOfWins, fewWins);
mainQuery.find({
success: function(results) {
// results contains a list of players that either have won a lot of games or won only a few games.
},
error: function(error) {
// There was an error.
}
});
您可以为新创建的Parse.Query添加其他约束充当“and”运算符。
请注意,在复合查询的子查询中,我们不支持GeoPoint或非过滤型约束(例如near、withinGeoBox、limit、skip、ascending/descending、include)。