sceee
sceee

Reputation: 2163

Cannot get FieldValue.increment working in Firestore emulator with Admin SDK

I am trying to get a simple atomic increase/decrease working in Firebase Cloud Functions with Firestore triggers. To test these, I want to execute local tests with the Firestore emulator.

But I always get the error FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: a custom object (found in field myfield)

My code is as simple as following

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

export const mytest = functions.firestore.document('my/{doc}').onUpdate(async (change, context) => {
  return perform();
});

export async function perform(): Promise<FirebaseFirestore.WriteResult> {
  const myDocRef = .... // this is a FirebaseFirestore.DocumentReference

  const decrement = admin.firestore.FieldValue.increment(1);
  return myDocRef.update({
    myfield: decrement
  });
}

In my tests I just call the perform function and then I receive the above error. It's definitely the FieldValue.increment that causes the error because if I just put a hardcoded number instead of the decrement in the update call, it works (updates to that hardcoded number).

I am on Firebase CLI 7.2.1 and emulator 1.6.2 which - according to Most efficient way to increment a value of everything in Firebase and https://github.com/firebase/firebase-js-sdk/issues/1799 should support FieldValue.increment in the emulator.

What am I doing wrong?

Upvotes: 4

Views: 1657

Answers (2)

Kumar Santanu
Kumar Santanu

Reputation: 701

Here's some example you can use it

const dbFieldValue = require('firebase-admin/firestore');

 const userPayout = Number(reward);
 transaction.update(userRef, { USER_WALLET_AMOUNT: FieldValue.increment(userPayout)});

in this way it works on emulator & production

Upvotes: 0

ryanpbrewster
ryanpbrewster

Reputation: 56

What version of firebase-admin are you using?

From your description it sounds like you're calling perform() directly from a Node.js script. I would recommend re-working your setup to more closely match what will actually happen in production: a client will connect directly to Firestore, create a document, and your function will be triggered.

Here's an example you can run that does this:

const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp();

exports.createItem = functions.https.onRequest(async (request, response) => {
  const item = await admin.firestore().collection("items").add({ addedAt: Date.now() });
  response.send(`added ${item.id}\n`);
});

const counter = admin.firestore().collection("counters").doc("items");
exports.increment = functions.firestore.document('items/{itemId}').onCreate(async (change, context) => {
  await counter.set({ total: admin.firestore.FieldValue.increment(1) }, { merge: true });
  const current = await counter.get();
  console.log(`incremented counter to ${current.data().total}`);
});

The first function, createItem, is an HTTP trigger that adds a document to the items/ collection. The second function is a Firestore trigger that increments a field in the counters/items document whenever a document is created.

When I run

curl -X POST http://localhost:5001/ryanpbrewster-test/us-central1/createItem

it creates a document and sends a response like

added LGOCapHSQtlXKIMEA8Do

This triggers the other function, which I can see in the emulator logs:

I function: Beginning execution of "increment"
>  incremented counter to 6

I function: Finished "increment" in ~1s

Upvotes: 1

Related Questions