Flutter应用中使用Parse优化查询性能的技术指南
在Flutter中解析查询食谱
介绍
我们已经看到如何使用 QueryBuilder 和 get 从Back4App检索单个 ParseObject。还有许多其他方法可以使用 QueryBuilder 检索数据 - 您可以一次检索多个对象,对您希望检索的对象使用条件等等。
在本指南中,您将深入了解 QueryBuilder 类,并查看您可以用来构建查询的所有方法。您将使用一个简单的数据库类和一些模拟数据来使用Flutter在Back4App上执行查询。
前提条件
- 一个连接到 Back4app 的 Flutter 应用。
- 一台运行 Android 或 iOS 的设备(或虚拟设备)。
目标
探索 QueryBuilder 类的不同方法。
QueryBuilder 类
任何 Parse 查询操作都使用 QueryBuilder 对象类型,这将帮助您在整个应用程序中从数据库中检索特定数据。
要创建一个新的 QueryBuilder,您需要将所需的 ParseObject 子类作为参数传递,这将包含您的查询结果。
重要的是要知道 QueryBuilder 只有在调用检索方法 query 后才会解析,因此可以设置查询并在实际调用之前链接多个修饰符。
您可以在官方文档中 这里阅读有关 QueryBuilder 类的更多信息。
在 Back4App 上使用 JavaScript 控制台
在您的 Back4App 应用程序的仪表板中,您会找到一个非常有用的 API 控制台,您可以直接运行 JavaScript 代码。在本指南中,您将使用它在 Back4App 中存储数据对象。在您的应用主仪表板上,转到 Core->API Console->Javascript.

保存您的数据对象
要在本指南中运行查询,您首先需要用一些数据填充您的应用。让我们创建一个名为 Profile 的示例类,它模拟一个社交媒体个人资料类,使用名人的名字和以下字段:
- 字符串类型 名称:
- 日期类型 生日:
- 数字(整数)类型 好友数量:
- 数组(字符串列表)类型 最爱食物:
- 数组(数字列表)类型 幸运数字:
- 地理点类型 最后登录位置:
这是 Parse.Object 类的创建代码,所以请在您的 API 控制台中运行它:
1 // Add Profile objects and create table
2 // Adam Sandler
3 let Profile = new Parse.Object('Profile');
4 Profile.set('name', 'Adam Sandler');
5 Profile.set('birthDay', new Date('09/09/1966'));
6 Profile.set('friendCount', 2);
7 Profile.set('favoriteFoods', ['Lobster', 'Bread']);
8 Profile.set('luckyNumbers', [2, 7]);
9 Profile.set('lastLoginLocation', new Parse.GeoPoint(37.38412167489413, -122.01268034622319));
10 await Profile.save();
11
12 // Britney Spears
13 Profile = new Parse.Object('Profile');
14 Profile.set('name', 'Britney Spears');
15 Profile.set('birthDay', new Date('12/02/1981'));
16 Profile.set('friendCount', 52);
17 Profile.set('favoriteFoods', ['Cake', 'Bread']);
18 Profile.set('luckyNumbers', [22, 7]);
19 Profile.set('lastLoginLocation', new Parse.GeoPoint(37.38412167489413, -122.01268034622319));
20 await Profile.save();
21
22 // Carson Kressley
23 Profile = new Parse.Object('Profile');
24 Profile.set('name', 'Carson Kressley');
25 Profile.set('birthDay', new Date('11/11/1969'));
26 Profile.set('friendCount', 12);
27 Profile.set('favoriteFoods', ['Fish', 'Cookies']);
28 Profile.set('luckyNumbers', [8, 2]);
29 Profile.set('lastLoginLocation', new Parse.GeoPoint(37.38412167489413, -122.01268034622319));
30 await Profile.save();
31
32 // Dan Aykroyd
33 // Creates related object Membership for this user only
34 let Membership = new Parse.Object('Membership');
35 Membership.set('name', 'Premium');
36 Membership.set('expirationDate', new Date('10/10/2030'))
37 await Membership.save();
38
39 Profile = new Parse.Object('Profile');
40 Profile.set('name', 'Dan Aykroyd');
41 Profile.set('birthDay', new Date('07/01/1952'));
42 Profile.set('friendCount', 66);
43 Profile.set('favoriteFoods', ['Jam', 'Peanut Butter']);
44 Profile.set('luckyNumbers', [22, 77]);
45 Profile.set('lastLoginLocation', new Parse.GeoPoint(37.38412167489413, -122.01268034622319));
46 Profile.set('premiumMembership', Membership);
47 await Profile.save();
48
49 // Eddie Murphy
50 Profile = new Parse.Object('Profile');
51 Profile.set('name', 'Eddie Murphy');
52 Profile.set('birthDay', new Date('04/03/1961'));
53 Profile.set('friendCount', 49);
54 Profile.set('favoriteFoods', ['Lettuce', 'Pepper']);
55 Profile.set('luckyNumbers', [6, 5]);
56 Profile.set('lastLoginLocation', new Parse.GeoPoint(-27.104919974838154, -52.61428045237739));
57 await Profile.save();
58
59 // Fergie
60 Profile = new Parse.Object('Profile');
61 Profile.set('name', 'Fergie');
62 Profile.set('birthDay', new Date('03/27/1975'));
63 Profile.set('friendCount', 55);
64 Profile.set('favoriteFoods', ['Lobster', 'Shrimp']);
65 Profile.set('luckyNumbers', [13, 7]);
66 Profile.set('lastLoginLocation', new Parse.GeoPoint(-27.104919974838154, -52.61428045237739));
67 await Profile.save();
68
69 console.log('Success!');运行此代码后,您现在应该在数据库中拥有一个 Profile 类,并创建了六个对象。您的新类应如下所示:

现在让我们来看一下每个 QueryBuilder 方法的示例,并简要解释它们的功能。请注意,此列表中的某些方法可以将 options 作为附加参数,但在大多数情况下,它仅与 masterKey 的使用相关,与本指南内容无关,因此在不相关的情况下将省略此可能性。
查询检索器
这些方法负责运行查询并检索其结果,始终存在于您的查询实现中。
//Retrieves the count of ParseObject results that meet the query criteria.
1 QueryBuilder<ParseObject> queryBuilder = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 var apiResponse = await queryPlayers.count();
3 if (apiResponse.success && apiResponse.result != null) {
4 int countGames = apiResponse.count;
5 }查询条件
这些方法使您能够对查询应用条件约束,这可以说是查询中最重要的操作。
请记住,这些操作都可以在检索结果之前链接,因此可以实现许多组合来满足您的查询需求。
//Requires that a key’s value does not match a value in an object returned by a different Parse.Query. Useful for multi-object querying.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 parseQuery.whereDoesNotMatchKeyInQuery(
3 'friendCount',
4 'friendCount',
5 QueryBuilder<ParseObject>(ParseObject('Profile'))
6 ..whereLessThan('friendCount', 50));
7 parseQuery.whereGreaterThan('friendCount', 10);
8 final apiResponse = await parseQuery.query();
9
10 if (apiResponse.success && apiResponse.results != null) {
11 for (var object in apiResponse.results as List<ParseObject>) {
12 print('${object.objectId} - Name: ${object.get<String>('name')} - friendCount: ${object.get<int>('friendCount')}');
13 }
14 }//Filters objects in which a string key value contains the provided text value. Be aware that this condition is case-sensitive.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 // This can be slow in large databases
3 parseQuery.whereContains('name', 'an');
4 final apiResponse = await parseQuery.query();
5
6 if (apiResponse.success && apiResponse.results != null) {
7 for (var object in apiResponse.results as List<ParseObject>) {
8 print('${object.objectId} - ${object.get<String>('name')}');
9 }
10 }//Filters objects in which a specific key’s value is equal to the provided value.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2
3 parseQuery.whereEqualTo('friendCount', 2);
4 final apiResponse = await parseQuery.query();
5
6 if (apiResponse.success && apiResponse.results != null) {
7 for (var o in apiResponse.results) {
8 final object = o as ParseObject;
9 print('${object.objectId} - ${object.get<String>('name')}');
10 }
11 }//Filters objects in which a specific key’s value is lesser than the provided value.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2
3 parseQuery.whereLessThan('birthDay', DateTime(1980, 08, 19));
4 final apiResponse = await parseQuery.query();
5
6 if (apiResponse.success && apiResponse.results != null) {
7 for (var object in apiResponse.results as List<ParseObject>) {
8 print('${object.objectId} - ${object.get<String>('name')}');
9 }
10 }//Requires that an object contained in the given key matches another query. Useful for multi-object querying.
1 final QueryBuilder<ParseObject> innerQuery = QueryBuilder<ParseObject>(ParseObject('Membership'));
2 innerQuery.whereGreaterThan('expirationDate', DateTime.now());
3
4 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
5
6 parseQuery.whereValueExists('premiumMembership', true);
7 parseQuery.whereMatchesQuery('premiumMembership', innerQuery);
8
9 final apiResponse = await parseQuery.query();
10
11 if (apiResponse.success && apiResponse.results != null) {
12 for (var object in apiResponse.results as List<ParseObject>) {
13 print('${object.objectId} - Name: ${object.get<String>('name')}');
14 }
15 }查询排序
在大多数查询中至关重要,排序可以在Parse中轻松实现,甚至可以在两个或多个排序约束之间链接。
//Sort the results in descending order, this can be chained without overwriting previous orderings. Multiple keys can be used to solve ordering ties.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 parseQuery.orderByDescending('name');
3 final apiResponse = await parseQuery.query();
4
5 if (apiResponse.success && apiResponse.results != null) {
6 for (var object in apiResponse.results as List<ParseObject>) {
7 print('${object.objectId} - ${object.get<String>('name')}');
8 }
9 }字段选择
这些方法影响查询结果中可以包含哪些字段值。
//Return all fields in the returned objects except the ones specified.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 parseQuery.excludeKeys(['name']);
3 final apiResponse = await parseQuery.query();
4
5 if (apiResponse.success && apiResponse.results != null) {
6 for (var object in apiResponse.results as List<ParseObject>) {
7 //Name = null
8 print('${object.objectId} - Name: ${object.get<String>('name')} - Birthday: ${object.get<DateTime>('birthDay')}');
9 }
10 }地理点查询
这些是特定于GeoPoint查询的方法。
//Return all fields in the returned objects except the ones specified.
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 parseQuery.whereNear(
3 'lastLoginLocation',
4 ParseGeoPoint(latitude: 37.38412167489413, longitude: -122.01268034622319)
5 );
6
7 final apiResponse = await parseQuery.query();
8
9 if (apiResponse.success && apiResponse.results != null) {
10 for (var object in apiResponse.results as List<ParseObject>) {
11 print('${object.objectId} - Name: ${object.get<String>('name')} - GeoPoint: ${object.get<ParseGeoPoint>('lastLoginLocation').toJson()}');
12 }
13 }1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 parseQuery.whereWithinKilometers(
3 'lastLoginLocation',
4 ParseGeoPoint(latitude: 37.38412167489413, longitude: -122.01268034622319),
5 100
6 );
7
8 final apiResponse = await parseQuery.query();
9
10 if (apiResponse.success && apiResponse.results != null) {
11 for (var object in apiResponse.results as List<ParseObject>) {
12 print('${object.objectId} - Name: ${object.get<String>('name')} - GeoPoint: ${object.get<ParseGeoPoint>('lastLoginLocation').toJson()}');
13 }
14 }分页
这些方法与分页工具相关,适用于将检索大量结果的查询。
1 final QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 parseQuery.setLimit(2);
3 final apiResponse = await parseQuery.query();
4
5 if (apiResponse.success && apiResponse.results != null) {
6 for (var object in apiResponse.results as List<ParseObject>) {
7 print('${object.objectId} - Name: ${object.get<String>('name')}');
8 }
9 }复合查询
这些方法将创建复合查询,可以将多个 ParseQuery 实例组合在一起以实现更复杂的结果。
//Compose a compound query that is the OR of the passed queries.
1 final QueryBuilder<ParseObject> query1 = QueryBuilder<ParseObject>(ParseObject('Profile'));
2 query1.whereGreaterThan('friendCount', 10);
3
4 final QueryBuilder<ParseObject> query2 = QueryBuilder<ParseObject>(ParseObject('Profile'));
5 query2.whereLessThan('friendCount', 50);
6
7 QueryBuilder<ParseObject> mainQuery = QueryBuilder.or(
8 ParseObject("Profile"),
9 [query1, query2],
10 );
11
12 final apiResponse = await mainQuery.query();
13
14 if (apiResponse.success && apiResponse.results != null) {
15 for (var object in apiResponse.results as List<ParseObject>) {
16 print('${object.objectId} - Name: ${object.get<String>('name')}');
17 }
18 }结论
在本指南的最后,您学习了如何执行 Parse 中的每种数据查询方法。在下一个指南中,您将学习 Flutter 中复杂的 Parse 查询。