2

I have these collection of items from firestore:

  • availability : true
  • stocks: 100
  • item: item1

enter image description here

I kind of wanted to decrement the stocks after submitting the form: I have these where() to compare if what the user chose is the same item from the one saved in the firestore.

  function incrementCounter(collref) {
    collref = firestore
      .collection("items")
      .doc()
      .where(selectedItem, "==", selectedItem);

    collref.update({
      stocks: firestore.FieldValue.increment(-1),
    });
  }

This is how I'll submit my form and I've set the incrementCounter() after saving it:

 const handleSubmit = (e) => {
    e.preventDefault();
    try {
      const userRef = firestore.collection("users").doc(id);
      const ref = userRef.set(
        {
         ....
          },
        },

        { merge: true }
      );

      console.log(" saved");
      incrementCounter();
    } catch (err) {
      console.log(err);
    }
  };

There's no error in submitting the form. However, the incrementCounter() is not working and displays this error:

TypeError: _Firebase_utils__WEBPACK_IMPORTED_MODULE_5__.firestore.collection(...).doc(...).where is not a function
JS3
  • 1,623
  • 3
  • 23
  • 52
  • I believe you are using FieldValue wrong. If your firestore variable is something like this ```const firestore = firebase.firestore()``` then you cannout use firestore in FieldValue of update section. You will have to use ```stocks: firebase.firestore.FieldValue.increment(-1)``` – Sulman Azhar Sep 08 '21 at 05:25
  • @SulmanAzhar I'm still having the same error – JS3 Sep 08 '21 at 05:29
  • Also confirm if `.where(selectedItem, "==", selectedItem)` is valid statement. For example, it's checking a field `itemName` has value `itemName`. Maybe share a screenshot of your document so we can confirm if that's what you need. – Dharmaraj Sep 08 '21 at 05:37
  • @Dharmaraj I've added a screenshot of the document. Thank you – JS3 Sep 08 '21 at 05:49
  • @Jenn that seems to be another problem. If you are trying to decrement doc fields where item is `item1`, then change it to: `.where("item", "==", selectedItem)` Apart from that, other issues are mentioned in my answer – Dharmaraj Sep 08 '21 at 05:50

2 Answers2

2

There are few problems here

  1. There should be async-await for both functions
  2. Your fieldValue should start from firebase.firestore.FieldValue not firestoreFieldValue
  3. Also where clause is used for collection, not doc() so remove that as well. Also I don't think this will update the full collection but do check it and see. (The error you are getting is because of this)

I don't know how you are importing firebase in this application and I don't know how you have declared firestore but mostly firestore variable is declared like this

const firestore = firebase.firestore();

In here firestore is a function, not a property But when you are using it in the FieldValue then it should be like

firebase.firestore.FieldValue.increment(-1),

Notice that firestore here is a property not a function

Your full code should be like this

async function incrementCounter(collref) {
    collref = firestore
      .collection("items")
      .where(selectedItem, "==", selectedItem);

    const newRef = await collref.get();
    for(let i in newRef.docs){
      const doc = newRef.docs[i];
      await doc.update({
       stocks: firebase.firestore.FieldValue.increment(-1),
     }); 
       // You can also batch this 
    }
  }



const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const userRef = firestore.collection("users").doc(id);
      const ref = await userRef.set(
        {
         ....
          },
        },

        { merge: true }
      );

      console.log(" saved");
      await incrementCounter();
    } catch (err) {
      console.log(err);
    }
  };
Sulman Azhar
  • 977
  • 1
  • 9
  • 26
  • Agreed that's why i added the comment of batch. Also ```forEach``` loops can cause some different problems as well that i once ran into. You can check that in this link. https://stackoverflow.com/questions/66062793/iterating-collection-and-trying-to-get-reference-field-inside-documents-get-i – Sulman Azhar Sep 08 '21 at 05:43
1

The where() method exists on a CollectionReference and not a DocumentReference. You also need to get references to those documents first so first get all the matching documents and then update all of them using Promise.all() or Batch Writes:

function incrementCounter() {
  // not param required  ^^
  const collref = firestore
      .collection("items")
      // .doc() <-- remove this
      .where(selectedItem, "==", selectedItem);
      //      ^^^                 ^^^
      //      doc field           field value
      //      "item"              {selectedItemName}

  collRef.get().then(async (qSnap) => {
    const updates = []
    qSnap.docs.forEach((doc) => {
      updates.push(doc.ref.update({ stocks: firebase.firestore.FieldValue.increment(-1) }))
    })
    await Promise.all(updates)
  })
}

If you are updating less than 500 documents, consider using batch writes to make sure all updates either fail or pass:

collRef.get().then(async (qSnap) => {
  const batch = firestore.batch()

  qSnap.docs.forEach((doc) => {
    batch.update(doc.ref, { stocks: firebase.firestore.FieldValue.increment(-1) })
  })

  await batch.commit()
})

You can read more about batch writes in the documentation

Dharmaraj
  • 47,845
  • 8
  • 52
  • 84