6
votes

Does anyone have a similar problem when trying to do multiple updates with batch? Here is my function:

admin.initializeApp();
const db = admin.firestore();
export const unfollowRemoveUser = functions.https.onCall((data, context) => {

        const user1id = data.user1
        const user2id = data.user2

        const user1DocRef = db.collection('users').doc(user1id)                 
    const user2DocRef = db.collection('users').doc(user2id)    

        const batch = db.batch();

        batch.update(user1DocRef, {followingNum : FieldValue.increment(-1)});
        batch.update(user2DocRef, {followersNum : FieldValue.increment(-1)});

        // Commit the batch
        return batch.commit().then(function () {
            // ...
        });


    });

Is something wrong with my function? I am doing this just like in documentation example for batched writes. I get this error:

Unhandled error Error: Update() requires either a single JavaScript object or an alternating list of field/value pairs that can be followed by an optional precondition. Value for argument \"dataOrField\" is not a valid Firestore document. Couldn't serialize object of type \"NumericIncrementTransform\" (found in field followingNum). Firestore doesn't support JavaScript objects with custom prototypes (i.e. objects that were created via the \"new\" operator).\n at WriteBatch.update (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/write-batch.js:367:23)\n at exports.unfollowRemoveUser.functions.https.onCall (/user_code/lib/index.js:131:11)\n at /user_code/node_modules/firebase-functions/lib/providers/https.js:330:32\n at next (native)\n at /user_code/node_modules/firebase-functions/lib/providers/https.js:28:71\n at __awaiter (/user_code/node_modules/firebase-functions/lib/providers/https.js:24:12)\n at func (/user_code/node_modules/firebase-functions/lib/providers/https.js:294:32)\n at corsHandler (/user_code/node_modules/firebase-functions/lib/providers/https.js:350:44)\n at cors (/user_code/node_modules/firebase-functions/node_modules/cors/lib/index.js:188:7)\n at /user_code/node_modules/firebase-functions/node_modules/cors/lib/index.js:224:17"

I searched and tried everything I could find but couldn't solve this problem, I even tried to use simple update to the document but I get the same error.

EDIT What should I do when I want batch to execute only if all operations can be executed successfully. Example: If I have first two updates on documents that do exist, they will update those values by -1 and then two delete operation on documents that do not exists, this won't cause an error to my function (values will be updated by -1 and delete won't do anything)

const batch = db.batch();
batch.update(user1DocRef, {followingNum : admin.firestore.FieldValue.increment(-1)});
        batch.update(user2DocRef, {followersNum : admin.firestore.FieldValue.increment(-1)});

        batch.delete(user1FollowingDocRef); //this doesn't exist
        batch.delete(user2FollowersDocRef); //this doesn't exist

        return batch.commit();

But if I first have two delete operations on documents that do not exists, whole function will fail

const batch = db.batch();

    batch.delete(user1FollowingDocRef); //this doesn't exist
    batch.delete(user2FollowersDocRef); //this doesn't exist

    batch.update(user1DocRef, {followingNum : admin.firestore.FieldValue.increment(-1)});
    batch.update(user2DocRef, {followersNum : admin.firestore.FieldValue.increment(-1)});


    return batch.commit();

I thought that anything that is attached to batch would execute only if all operations can be successfully executed

1
I would expect this to work. How did you import the FieldValue symbol? I don't see that here.Doug Stevenson
@DougStevenson import * as functions from 'firebase-functions'; import * as admin from 'firebase-admin'; import { FieldValue } from '@google-cloud/firestore'; also in package.json "dependencies": { "@google-cloud/firestore": "^1.2.0", "firebase-admin": "^7.3.0", "firebase-functions": "^2.3.0" },Alen
If you have a second question, please post it separately.Doug Stevenson
awesome! I've mistakenly imported "@google-cloud/firestore" then called FieldValue.increment() from it, and the correct approach is importing directly from the admin.firestore.FieldValue.increment()Guilherme Matuella
Yes I had the same issue as @Guilherme. It was working fine until I updated my firestore versions and also updated to node 10.MadMac

1 Answers

9
votes

I have had a similar problem with FieldValue. As Doug mentioned you need to 'import' the FieldValue to use the increment() method.

You could do this inline.

batch.update(user1DocRef, {followingNum : admin.firestore.FieldValue.increment(-1)});
batch.update(user2DocRef, {followersNum : admin.firestore.FieldValue.increment(-1)});

Or you could define a constant with a shorter name.

admin.initializeApp();
const db = admin.firestore();
const firestore = admin.firestore;
export const unfollowRemoveUser = functions.https.onCall((data, context) => {

    const user1id = data.user1
    const user2id = data.user2

    const user1DocRef = db.collection('users').doc(user1id)                 
    const user2DocRef = db.collection('users').doc(user2id)    

    const batch = db.batch();

    batch.update(user1DocRef, {followingNum : firestore.FieldValue.increment(-1)});
    batch.update(user2DocRef, {followersNum : firestore.FieldValue.increment(-1)});

    // Commit the batch
    return batch.commit().then(function () {
        // ...
    });


});