skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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
      });
    });
    

  2. It is not possible to use the server-side timestamp as a key in the document data with Firestore. The reason is that Firestore requires that all keys are present as static payload of the request, while the key is only determined on the server.

    So if you want to use a server-side timestamp as the key, you will indeed have to first force it to be written as a value to the document, then read that value back with an SDK, and use it as a key in a subsequent update.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search