Reputation: 2163
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
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
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