Ordering Firestore documents in descending order in Flutter?

6.2k views Asked by At

I want to order Firestore documents in descending order according to the timestamp they have uploaded. I mean when I upload a new photo it should appear on the top of the image grid that I have made. Here I used orderBy and I passed true for the parameter descending (bottom of the code in the get images method). by default it is false and then the image grid is ordering ascending fine. When I upload a new image it works fine with ascending order. But when I set true to parameter descending inside the orderBy it is not working. It makes a duplicate image of previously uploaded one (see the image link below). But when I restart the app it is ordered descending. ascending is updating realtime but descending is not. We just only have to change the boolean value of descending parameter to get either ascending order or descending order. I would be grateful if someone can help me with this issue. Here is my code,

class DatabaseService {

  final String uid;

  DatabaseService({this.uid});

  // collection reference
  final CollectionReference imageCollection = Firestore.instance.collection('images');

  // creating new document for a image user and updating existing image data
  Future updateImageData(String location, String url) async{
    return await imageCollection.document(uid).setData({
      'location': location,
      'url': url,
      'timestamp': FieldValue.serverTimestamp(),
    });
  }
  
  // image list from snapshot
  List<GridImage> _imageListFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      return GridImage(
        url: doc.data['url'] ?? '',
        location: doc.data['location'] ?? '',
        timestamp: doc.data['timestamp'].toString() ?? ''
      );
    }).toList();
  }

  // get image stream
  Stream<List<GridImage>> get images {
    return imageCollection.orderBy('timestamp', descending: true).snapshots().map(_imageListFromSnapshot);
  }

}

duplicating a previous image

2

There are 2 answers

1
Samuel Romero On

As Meryn commented, you should use am index to solve this issue. Actually there are a lot of examples about this (order by not working and firestore order by) and in all of them it is recommended to use the index. You can follow the instructions here to do it

You would have to go to your firestore console and index the fields you are ordering by.

Go to: indexes >> Composite.

Next: add the index and wait for it to be active.

2
Siddharth jha On

Modify GridImage to use equatable as such

import 'package:equatable/equatable.dart';

class GridImage extends Equatable {
  final String location;
  final String url;
  final String timestamp;

  GridImage({this.location,this.url,String timestamp}):timestamp = timestamp ?? Timestamp.now().toString(); // incase timestamp is null
  

  @override
  List<Object> get props => [location,url];
}

Modify your _imageListFromSnapshot function as such

List<GridImage> _imageListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
  return GridImage(
    url: doc.data['url'] ?? '',
    location: doc.data['location'] ?? '',
    timestamp: doc.data['timestamp']?.toString() // remove null check we are already handling it inside the model and use null safe call ( ?. )
  );
}).toList().toSet().toList(); // convert the list to set to remove duplicates

}