2

What I want

To order ListView based on server timestamp

My code

Adding to firestore collection:

onPressed: () {
FirebaseFirestore.instance.collection('things').add(
  {
    // some code
    'timestamp': FieldValue.serverTimestamp(),
  },
);

Get data from the firestore and ordered them based on the server timestamp

return StreamBuilder<QuerySnapshot>(
  stream: FirebaseFirestore.instance.collection('things').orderBy('timestamp').snapshots(),

Expected behavior

List View are displayed ordered based on the server timestamp

What I got

This error:

Expected a value of type 'String', but got one of type 'Timestamp'

What I've tried

I've tried adding toString() when sending the data to the firestore: 'timestamp': FieldValue.serverTimestamp().toString(), but then the data on the firestore didn't store timestamp, instead they stored FieldValue(Instance of 'FieldValueWeb').

I know that I probable have to convert them to String when I'm getting the data from the firestore, but I have no idea how to do that. I've tried adding in toString() when getting the data into the stream as such:

stream: FirebaseFirestore.instance.collection('things').orderBy('timestamp').toString().snapshots()

but then it shows below error and won't compile.

The method 'snapshots' isn't defined for the type 'String'.

The official document does not say anything about converting them to String either.

If anybody knows how to solve this please help me, I'm really stuck here.


Full StreamBuilder and ListView code

return StreamBuilder<QuerySnapshot>(
  stream: _firestore.collection('things').orderBy('timestamp').snapshots(),
  builder: (context, snapshot) {
    List<Text> putDataHere = [];

    final things = snapshot.data.docs;
    for (var thing in things) {
      final myData = Map<String, String>.from(thing.data());
      final myThing = myData['dataTitle'];
      final thingWidget = Text(myThing);
      putDataHere.add(thingWidget);
    }
    return Expanded(
      child: ListView(
        children: putDataHere,
      ),
    );
  },
);
Sae
  • 79
  • 7

3 Answers3

1

You can try this:

Firestore.instance
     .collection("things")
     .orderBy('createdAt', descending: true or false).getDocuments()

And then you can store createdAt on your client side with Timestamp, and you can get current timestamp with Timestamp.now()

Jaime Ortiz
  • 1,089
  • 10
  • 14
1

Since the expected behaviour is that ListView items are ordered based on the server timestamp, you can just sort the list after you've gotten it from Firestore.

    final things = snapshot.data.docs;
    things.sort((a, b) {
        return (a['timestamp'] as Timestamp).compareTo(b['timestamp'] as Timestamp);
    });

Victor Eronmosele
  • 7,040
  • 2
  • 10
  • 33
  • 1
    I didn't use your code but that gave me a hint, it turns out the problem is not the way it got data from the firebase, `orderBy` can take `Timestamp` just fine. The problem was on my Map. I totally forgot about it but I set it to `Map`. Now that I also have `Timestamp` type, it complains that it can't be converted. So I just changed the Map to `Map` and it solves the problem. – Sae Jun 10 '21 at 13:10
0

The problem was totally different from what I had initially thought.

I honestly forgot that when I retrieve the data from the Firestore to process it, I set my Map to Map<String, String>, it was fine before because I only had String, but now that I have Timestamp type, it doesn't work.

The answer to the question is just simply changing the Map<String, String> to Map<String, dynamic>

Sae
  • 79
  • 7