Search code examples
flutterdartgoogle-cloud-firestore

Flutter set record with server timestamp as key


I need to add field to document when key is the Firebase/Firestore server timestamp. The only working solution i found till now is first create record with timestamp as value with FieldValue.serverTimestamp(), than read it from Firestore and than use received value for a key. This solution looks ugly and I don't think it is correct one.

Using FieldValue.serverTimestamp().toString() as key, add "FieldValue(Instance of 'MethodChannelFieldValue')"string instead of actual timestamp value.

The code looks like:

  saveUserAnswersToFirestore(List<RemoteAnswerModel> answers) async {
    User? user = FirebaseAuth.instance.currentUser;

    DocumentReference<Map<String, dynamic>> userAnswerDoc = FirebaseFirestore.instance
        .collection('answers')
        .doc('${user?.phoneNumber}');

    final now = '${Timestamp.now().millisecondsSinceEpoch}'; //FieldValue.serverTimestamp().toString();
    var answersMap = answers.map((e) => e.toJson()).toList();
    try {
      await userAnswerDoc.update({
        now : answersMap
      });
    } catch (e) {
      await userAnswerDoc.set({
        now : answersMap
      });
    }
  }

Any thoughts?

This is how the result should look like:

enter image description here


Solution

  • Ok. Final solution is to use transaction to make sure that no garbage records will created if any step is failed. The Transaction will create cache record for every user just to store the timestamp record, read its value and than save original record with recieved value as key:

    saveUserAnswersToFirestore(List<RemoteAnswerModel> answers) async {
    User? user = FirebaseAuth.instance.currentUser;
    
    var userCache = FirebaseFirestore.instance
        .collection('cache')
        .doc('${user?.phoneNumber}');
    
    var userAnswerDoc = FirebaseFirestore.instance
        .collection('answers')
        .doc('${user?.phoneNumber}');
    
    FirebaseFirestore.instance.runTransaction((transaction) async{
      // 1. Create timestamp record
      await userCache.set({
        'timestamp' : FieldValue.serverTimestamp()
      });
      // 2. Read timestamp value stored in step 1
      DocumentSnapshot<Map?> doc = await userCache.get();
      Timestamp timestampObj = doc.data()?.values.first;
      var timestamp = timestampObj.toDate().millisecondsSinceEpoch;
      print("timestamp: ${timestamp}");
    
      // 3. Create record with timestamp as key
      var answersMap = answers.map((e) => e.toJson()).toList();
      await userAnswerDoc.set({
        '${timestamp}' : answersMap
      });
    });