Introduction
As part of a little side project, I wanted to log all Firestore writes for a user to a user specific collection that I can use to display a user’s activity. I was able to accomplish this using Audit Logs, Pub/Sub, and Cloud Functions.
Requirements
- Log all Firestore writes for a user, ignore reads
- Access the writes as an activity collection for the user,
users/{userId}/activity
Architecture
There are a few moving parts to this solution, but it’s pretty automatic.
- Audit Logs are enabled for Firestore writes
- Logs are sent to a Pub/Sub topic via a sink
- Cloud Function is triggered by Pub/Sub message
import * as firebaseAdmin from "firebase-admin";
import * as functions from "firebase-functions";
export default functions.pubsub
.topic("firestore-activity")
.onPublish(async (message) => {
const { data } = message;
const { timestamp, protoPayload } = JSON.parse(
Buffer.from(data, "base64").toString()
);
const uid =
protoPayload.authenticationInfo.thirdPartyPrincipal.payload.user_id;
const writes = protoPayload.request.writes;
const activityRef = firebaseAdmin
.firestore()
.collection("users")
.doc(uid)
.collection("activity");
await Promise.all(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
writes.map((write: any) => {
activityRef.add({ write, timestamp });
})
);
});
- Cloud Function writes to Firestore
And that's it. I now have a /user/{userId}/activity
collection!