Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firestore get value of Field.increment after update without reading the document data

Is there a way to retrieve the updated value of a document field updated using firestore.FieldValue.increment without asking for the document?

var countersRef = db.collection('system').doc('counters');

await countersRef.update({
    nextOrderCode: firebase.firestore.FieldValue.increment(1)
});

// Get the updated nextOrderCode without asking for the document data?

This is not cost related, but for reliability. For example if I want to create a code that increases for each order, there is no guaranty that if >= 2 orders happen at the same time, will have different codes if I read the incremental value right after the doc update resolves, because if >= 2 writes happen before the first read, then at least 2 docs will have the same code even if the nextOrderCode will have proper advance increment.

like image 359
Christos Lytras Avatar asked Jul 08 '19 19:07

Christos Lytras


2 Answers

Update

Possible now, check other answer.


It's not possible. You will have to read the document after the update if you want to know the value.

If you need to control the value of the number to prevent it from being invalid, you will have to use a transaction instead to make sure that the increment will not write an invalid value. FieldValue.increment() would not be a good choice for this case.

like image 156
Doug Stevenson Avatar answered Sep 19 '22 23:09

Doug Stevenson


We can do it by using Firestore Transactions, like incremental worked before Field.increment feature:

try {
  const orderCodesRef = admin.firestore().doc('system/counters/order/codes');
  let orderCode = null;
  await admin.firestore().runTransaction(async transaction => {
    const orderCodesDoc = await transaction.get(orderCodesRef);
    if(!orderCodesDoc.exists) {
      throw { reason: 'no-order-codes-doc' };
    }

    let { next } = orderCodesDoc.data();
    orderCode = next++;
    transaction.update(orderCodesRef, { next });
  });

  if(orderCode !== null) {
    newOrder.code = orderCode;
    const orderRef = await admin.firestore().collection('orders').add(newOrder);

    return success({ orderId: orderRef.id });
  } else {
    return fail('no-order-code-result');
  }
} catch(error) {
  console.error('commitOrder::ERROR', error);
  throw errors.CantWriteDatabase({ error });
}
like image 25
Christos Lytras Avatar answered Sep 17 '22 23:09

Christos Lytras