Sunday, 9 May 2021

Firestore read/update array of documents in one transaction

I created inventory management using Firestore. User can update single inventory items (products) and create purchases and invoices. When user creates purchase (or invoice) application updates multiple products quantities,creates event for each product change, creates new purchase document (where i store purchase number and array of products and more...) and increments "purchase number".

The code:

const db_user = db.collection("users").doc(userUID);
let products = db_user.collection("products");
let productEvents = db_user.collection("productEvents");

jQuery.each(productsArrayToUpdate, function (index, value) {
    let product = products.doc(productsArrayToUpdate[index][0]);
    let outQTY = productsArrayToUpdate[index][1];
    //...
    db.runTransaction(function (transaction) {
        return transaction.get(product).then(function (doc) {
            if (!doc.exists) {
                Swal.fire("Document does not exist!");
            }
            //...
            let newProductQTY = (doc.data().productQTY) ? doc.data().productQTY - outQTY + inQTY : 0 - outQTY + inQTY;
            //1. UPDATE PRODUCT DOC WITH NEW QUANTITY
            transaction.update(product, {
                productQTY: newProductQTY,
                //...
            });
            //2. CREATE NEW DOC IN ANOTHER COLLECTION WITH THIS PRODUCT EVENT
            transaction.set(productEvents.doc(), {
                productSKU: doc.data().productSKU,
                //....
            });
        });
    }).then(function () {
        //...  
    }).catch(function (error) {
        //...
    });
});

//3. CREATE PURCHASE DOCUMENT FOR ALL
db_user.get().then(function (doc) {
    if (doc.exists) {
        let purchaseDoc = db_user.collection("purchases").doc();
        purchaseDoc.set({
            purchaseNumber: purchaseNumber,
            purchasePositions: dataTablePurchaseRows,
            //...
        });
        db_user.update({
            //INCREMENT PURCHASE DOCUMENT NUMBER
            purchaseNumber: firebase.firestore.FieldValue.increment(1)
        }).then(function () {
            //...
        }).catch(function (error) {
            //..
        });
    } else {
        //...
    }
}).catch(function (error) {
    //...
});

It works OK but sometimes it fails and I have mess in my inventory:( So my question is how to put array of docs to read/update and set new docs(for each event) inside of one transaction and then create my purchase document with increment number if transaction pass.

something like this:

return db.runTransaction(function (transaction) {

    productsArrayToUpdate.forEach(function (element,index) {

        let product = products.doc(element[0]);
        let outQTY = element[1];
        ...
        return transaction.get(product).then(function (doc) {
            transaction.update(product, {
                productQTY: newProductQTY,
                [warehouseIN]: newSelectedWarehouseQTYIN,
                productInventoryStatus: inventoryStatus
            });
          transaction.set(productEvents.doc(), {
                productSKU: doc.data().productSKU,
          //...
    }
}

EDIT: I found this Firebase: Transaction read and update multiple documents

Could someone convert it it to foreach loop please:

let promise = await admin.firestore().runTransaction(transaction => {
  var post = transaction.get(docRef);
  var anotherPost = transaction.get(anotherDocRef);

  if (post.exists && anotherPost.exists) {
    var newLikes = (post.data().likes || 0) + 1;
    await transaction.update(docRef, { likes: newLikes });
    newLikes = (anotherPost.data().likes || 0) + 1;
    await transaction.update(anotherdocRef, { likes: newLikes });
  }
})


from Firestore read/update array of documents in one transaction

No comments:

Post a Comment