Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 6b87cc2

Browse files
[cloud_firestore] Support for map fields in document pagination (#1781)
1 parent 02ff568 commit 6b87cc2

5 files changed

Lines changed: 66 additions & 3 deletions

File tree

packages/cloud_firestore/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.12.6
2+
3+
* Support for `orderBy` on map fields (e.g. `orderBy('cake.flavor')`) for
4+
`startAtDocument`, `startAfterDocument`, `endAtDocument`, and `endBeforeDocument` added.
5+
16
## 0.12.5+2
27

38
* Automatically use version from pubspec.yaml when reporting usage to Firebase.

packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,16 @@ private Object[] getDocumentValues(
129129
if (orderBy != null) {
130130
for (List<Object> order : orderBy) {
131131
String orderByFieldName = (String) order.get(0);
132-
data.add(documentData.get(orderByFieldName));
132+
if (orderByFieldName.contains(".")) {
133+
String[] fieldNameParts = orderByFieldName.split("\\.");
134+
Map<String, Object> current = (Map<String, Object>) documentData.get(fieldNameParts[0]);
135+
for (int i = 1; i < fieldNameParts.length - 1; i++) {
136+
current = (Map<String, Object>) current.get(fieldNameParts[i]);
137+
}
138+
data.add(current.get(fieldNameParts[fieldNameParts.length - 1]));
139+
} else {
140+
data.add(documentData.get(orderByFieldName));
141+
}
133142
}
134143
}
135144
data.add((boolean) arguments.get("isCollectionGroup") ? document.get("path") : documentId);

packages/cloud_firestore/example/test_driver/cloud_firestore.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,5 +210,44 @@ void main() {
210210
await doc1.delete();
211211
await doc2.delete();
212212
});
213+
214+
test('pagination with map', () async {
215+
// Populate the database with two test documents.
216+
final CollectionReference messages = firestore.collection('messages');
217+
final DocumentReference doc1 = messages.document();
218+
// Use document ID as a unique identifier to ensure that we don't
219+
// collide with other tests running against this database.
220+
final String testRun = doc1.documentID;
221+
await doc1.setData(<String, dynamic>{
222+
'cake': <String, dynamic>{
223+
'flavor': <String, dynamic>{'type': 1, 'test_run': testRun}
224+
}
225+
});
226+
227+
final DocumentSnapshot snapshot1 = await doc1.get();
228+
final DocumentReference doc2 = await messages.add(<String, dynamic>{
229+
'cake': <String, dynamic>{
230+
'flavor': <String, dynamic>{'type': 2, 'test_run': testRun}
231+
}
232+
});
233+
234+
QuerySnapshot snapshot;
235+
List<DocumentSnapshot> results;
236+
237+
// One pagination call is enough as all of the pagination methods use the same method to get data internally.
238+
snapshot = await messages
239+
.orderBy('cake.flavor.type')
240+
.where('cake.flavor.test_run', isEqualTo: testRun)
241+
.startAtDocument(snapshot1)
242+
.getDocuments();
243+
results = snapshot.documents;
244+
245+
expect(results.length, 2);
246+
expect(results[0].data['cake']['flavor']['type'], 1);
247+
expect(results[1].data['cake']['flavor']['type'], 2);
248+
249+
await doc1.delete();
250+
await doc2.delete();
251+
});
213252
});
214253
}

packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@
3232
for (id item in orderBy) {
3333
NSArray *orderByParameters = item;
3434
NSString *fieldName = orderByParameters[0];
35-
[values addObject:[documentData objectForKey:fieldName]];
35+
if ([fieldName rangeOfString:@"."].location != NSNotFound) {
36+
NSArray *fieldNameParts = [fieldName componentsSeparatedByString:@"."];
37+
NSDictionary *currentMap = [documentData objectForKey:[fieldNameParts objectAtIndex:0]];
38+
for (int i = 1; i < [fieldNameParts count] - 1; i++) {
39+
currentMap = [currentMap objectForKey:[fieldNameParts objectAtIndex:i]];
40+
}
41+
[values addObject:[currentMap objectForKey:[fieldNameParts
42+
objectAtIndex:[fieldNameParts count] - 1]]];
43+
} else {
44+
[values addObject:[documentData objectForKey:fieldName]];
45+
}
3646
}
3747
}
3848
if (isCollectionGroup) {

packages/cloud_firestore/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for Cloud Firestore, a cloud-hosted, noSQL database
33
live synchronization and offline support on Android and iOS.
44
author: Flutter Team <flutter-dev@googlegroups.com>
55
homepage: https://github.com/flutter/plugins/tree/master/packages/cloud_firestore
6-
version: 0.12.5+2
6+
version: 0.12.6
77

88
flutter:
99
plugin:

0 commit comments

Comments
 (0)