Firebase Cloud Function batch write update document overwrote the entire document?

Viewed 82

The following Cloud Function has a batch write operation that, in part, updates a single field in a document. This overwrote the entire document and now the document has a single field joinedCount: -1. Is this not the way to update individual fields in documents without overwriting them?

exports.deleteUserTEST = functions.https.onCall(async (data, _context) => {
    const uId = data.userId;
    const db = admin.firestore();

    try {
        const batch = db.batch();
        const settingsDoc = await db.collection("userSettings").doc(uId).get();
        const joinedIds = settingsDoc.get("private.joinedIds");

        Object.keys(joinedIds).forEach(function(jId, _index) {
            batch.update(
                db.collection("profiles").doc(jId),
                {
                    private: {
                        joinedCount: admin.firestore.FieldValue.increment(-1), // <-- the culprit
                    },
                },
            );
        });
        await batch.commit();
    } catch (error) {
        throw new functions.https.HttpsError("unknown", "Failed the delete the user's content.", error);
    }
    return Promise.resolve(uId);
});
1 Answers

Moving the solution found in the comments by @Dharmaraj into a community answer, this problem was caused by the structure of the document.

Since all the data in the document was inside the private map field, passing a new map through the update method would make it appear that the entire document was being overwritten instead of updated.

In this case, you would need to access the fields through dot notation. This allows those inner fields within the map to be updated, without replacing the entire private map:

Object.keys(joinedIds).forEach(function(jId, _index) {
    batch.update(db.collection("profiles").doc(jId), {
        "private.joinedCount": admin.firestore.FieldValue.increment(-1)
    });
});

Another example from the documentation:

import { doc, setDoc, updateDoc } from "firebase/firestore"; 

// Create an initial document to update.
const frankDocRef = doc(db, "users", "frank");
await setDoc(frankDocRef, {
    name: "Frank",
    favorites: { food: "Pizza", color: "Blue", subject: "recess" },
    age: 12
});

// To update age and favorite color:
await updateDoc(frankDocRef, {
    "age": 13,
    "favorites.color": "Red"
});
Related