Photo by Rita Vicari on Unsplash

Community-driven data modifications using Cloud Functions

Kyle Welsby
The Startup
Published in
4 min readDec 18, 2019

--

Prelude

I’m working on a side project around my paid client work and weekly Soulection Tracklists publications called TracksPlayed (a spin-off from Soulection Tracklists).

With this new project, I’m exploring new technologies and processes to improve features I wish I had in Soulection Tracklists.

Here is an insight into a process that I think will allow the community to suggest changes to data (I’m also open to suggestions in the comment section if you have other solutions).

For this; will assume you’re using Firebase FireStore (a real-time NoSQL database by Google), but can easily be adapted to work with MongoDB and PostgreSQL projects.

Suggestions Collection

Let’s start off with a database collection called suggestions here we will have a structure like the following.

{ "path": "string", "key": "string", "value": "string", "createdAt": "datetime", "approvedAt": "datetime", "committedAt": "datetime" }

Let’s take a moment to explain each part of this schema.

A reference to the document we want to change for example, product/1, the path will contain the collection and document ID so we can find it later.

The value within the document, we will want to change the given value. Let’s say a someone wants to suggest a name change to product/1 the key would be name which leads us to;

Suggestions Moderation

Depending on your use case you can have a site admin moderation view or a per account moderation view which would be scoped to only the suggestions of the path match any of the documents the account has access to.

I’m not going to cover the per account moderation view in order to keep this writing short. Feel free to explore this yourself.

We’ll assume a simple administration view where we will fetch all documents in the suggestions collection that has a null in the approvedAt column.

Approving the suggestion will set the approvedAt value to the current date new Date().

Handling Suggestions

On Firebase we can set a Firebase Function to listen for changes in FireStore when we update a document. In MongoDB or PostgreSQL you can add triggers, and execute a Cloud Function/Lambda.

We’ll aim to do to the following in the Cloud Function;

  1. Set the value of the suggested path key to the value given.
  2. Set the committedAt to the current time.
  3. Ensure we do not handle the approval multiple times

Start with a simple function to listen to the suggestions documents.

exports.onSuggestionApproved = functions.firestore.document('suggestions/{documentId}')
.onUpdate((snap, context) => {
// ... do something when the document is updated
})
})

setting the value of the suggestion

We’ll use the path to get the document reference and can set the key and value.

let ref = db.doc(data.path)
ref.set({
[data.key]: data.value,
}, { merge: true })

Finishing the function

The ref.set returns a Promise, and we will have two promises to wait for. We need to add them to an array and wait for them all to resolve before completing the function.

Change each instance of ref.set to push to a promises array

let promises = []
promises.push(
ref.set(/* ... */)
)

Return once all the promises are successfully resolved.

return Promise.all(promises)

Putting it all together

exports.onSuggestionApproved = functions.firestore.document('suggestions/{documentId}')
.onUpdate((snap, context) => {
const before = snap.before.data()
const data = snap.after.data()
let promises = []
/**
* @todo add approvedBy to ensure the changing document can be modified by a member of the account
*/
if (!before.approvedAt && data.approvedAt) {
let ref = db.doc(data.path)
promises.push(
ref.set({
[data.key]: data.value,
}, { merge: true })
)
promises.push(
snap.after.ref.set({
committedAt: new Date()
}, { merge: true })
)
}
return Promise.all(promises)
})

Now we have a simple Cloud Function that listens for changes in a Firestore document and will trigger changes in a corresponding document once the approvedAt is defined.

Notable Concerns

In the final code, you can see a @todo. The power of this function allows any changes to any document. To avoid people setting themselves as administrators or committing changes to documents they have not authorisation on, we need to add a permission check.
This is a conditional check that would have to be made before the document is changed.

Conclusion

Allowing your community to make changes to database documents allows a whole wealth of crowd-sourced information.
This example allows the functionality without having to enable or replicate the code for each place we want to implement the feature on.

Having a suggestions column allows changes to be staged and moderated before they are committed. Also retains a history of the submitted changes for auditing should that be of interest to you.

If you have any better solutions or questions please comments below.

Originally published at https://dev.to on December 18, 2019.

--

--

Kyle Welsby
The Startup

Code Wrangler, Travel & Food Photographer, and Maker of http://soulectiontracklists.com . From Great Britain 🇬🇧