diff --git a/manifest.json b/manifest.json index f38bb05..46d7e33 100644 --- a/manifest.json +++ b/manifest.json @@ -3,6 +3,9 @@ { "metadata": "/snippets/functions/third-party/manifest.json" }, + { + "metadata": "/snippets/functions/boilerplate/manifest.json" + }, { "metadata": "/snippets/functions/mongodb-crud/manifest.json" }, @@ -19,5 +22,5 @@ "metadata": "/snippets/triggers/project/manifest.json" } ], - "version": "d04d084298c27e7c755e36c9f61c00ac9e836f56" + "version": "86e6c130f442b25a8cabba7e140acde80e58f085" } diff --git a/snippets/functions/boilerplate/databaseTrigger.js b/snippets/functions/boilerplate/databaseTrigger.js new file mode 100644 index 0000000..508921d --- /dev/null +++ b/snippets/functions/boilerplate/databaseTrigger.js @@ -0,0 +1,40 @@ +exports = async function (changeEvent) { + // A Database Trigger will always call a function with a changeEvent. + // Documentation on ChangeEvents: https://www.mongodb.com/docs/manual/reference/change-events + + // This sample function will listen for events and replicate them to a collection in a different Database + + // Access the _id of the changed document: + const docId = changeEvent.documentKey._id; + + // Get the MongoDB service you want to use (see "Linked Data Sources" tab) + const serviceName = "mongodb-atlas"; + const databaseName = "other_db_name"; + const collection = context.services + .get(serviceName) + .db(databaseName) + .collection(changeEvent.ns.coll); + + // Get the "FullDocument" present in the Insert/Replace/Update ChangeEvents + try { + // If this is a "delete" event, delete the document in the other collection + if (changeEvent.operationType === "delete") { + await collection.deleteOne({ _id: docId }); + } + + // If this is an "insert" event, insert the document into the other collection + else if (changeEvent.operationType === "insert") { + await collection.insertOne(changeEvent.fullDocument); + } + + // If this is an "update" or "replace" event, then replace the document in the other collection + else if ( + changeEvent.operationType === "update" || + changeEvent.operationType === "replace" + ) { + await collection.replaceOne({ _id: docId }, changeEvent.fullDocument); + } + } catch (err) { + console.log("error performing mongodb write: ", err.message); + } +}; diff --git a/snippets/functions/boilerplate/eventbridgeErrorFunction.js b/snippets/functions/boilerplate/eventbridgeErrorFunction.js new file mode 100644 index 0000000..fb8c4f5 --- /dev/null +++ b/snippets/functions/boilerplate/eventbridgeErrorFunction.js @@ -0,0 +1,18 @@ +exports = async function (error, changeEvent) { + // This sample function will log additional details if the error is not + // a DOCUMENT_TOO_LARGE error + if (error.code === "DOCUMENT_TOO_LARGE") { + console.log("Document too large error"); + + // Comment out the line below in order to skip this event and not suspend the Trigger + throw new Error(`Encountered error: ${error.code}`); + } + + console.log("Error sending event to EventBridge"); + console.log(`DB: ${changeEvent.ns.db}`); + console.log(`Collection: ${changeEvent.ns.coll}`); + console.log(`Operation type: ${changeEvent.operationType}`); + + // Throw an error in your function to suspend the trigger and stop processing additional events + throw new Error(`Encountered error: ${error.message}`); +}; diff --git a/snippets/functions/boilerplate/generalFunction.js b/snippets/functions/boilerplate/generalFunction.js new file mode 100644 index 0000000..3c6055f --- /dev/null +++ b/snippets/functions/boilerplate/generalFunction.js @@ -0,0 +1,42 @@ +exports = async function (arg) { + // This default function will get a value and find a document in MongoDB + // To see plenty more examples of what you can do with functions see: + // https://www.mongodb.com/docs/atlas/app-services/functions/ + + // Find the name of the MongoDB service you want to use (see "Linked Data Sources" tab) + const serviceName = "mongodb-atlas"; + + // Update these to reflect your db/collection + const dbName = "db_name"; + const collName = "coll_name"; + + // Get a collection from the context + const collection = context.services + .get(serviceName) + .db(dbName) + .collection(collName); + + let findResult; + try { + // Get a value from the context (see "Values" tab) + // Update this to reflect your value's name. + const valueName = "value_name"; + const value = context.values.get(valueName); + + // Execute a FindOne in MongoDB + findResult = await collection.findOne({ + owner_id: context.user.id, + fieldName: value, + argField: arg, + }); + } catch (err) { + console.log("Error occurred while executing findOne:", err.message); + + return { error: err.message }; + } + + // To call other named functions: + // const result = context.functions.execute("function_name", arg1, arg2); + + return { result: findResult }; +}; diff --git a/snippets/functions/boilerplate/manifest.json b/snippets/functions/boilerplate/manifest.json new file mode 100644 index 0000000..63348fa --- /dev/null +++ b/snippets/functions/boilerplate/manifest.json @@ -0,0 +1,31 @@ +{ + "category": "Boilerplate Template by Function Type", + "categoryId": "4756072f-b3c7-4469-b038-cdf6b346789c", + "viewType": "functionSnippet", + "snippets": [ + { + "id": "7c84ed29-b8b2-466c-af3d-c240889d3112", + "title": "Database Trigger", + "snippet": "/databaseTrigger.js", + "description": "Example shows a template for a DB trigger function, which always accepts a changeEvent as an argument." + }, + { + "id": "ba6113d7-5e52-48e4-8ab4-03df30c0d61a", + "title": "Scheduled Trigger", + "snippet": "/scheduledTrigger.js", + "description": "Shows an example of a Scheduled Trigger function, which will always call a function without arguments." + }, + { + "id": "1dca4a58-c150-4a8e-b602-9edf5c338f3d", + "title": "General Function", + "snippet": "/generalFunction.js", + "description": "Example of a default function that will get a value and find a document in MongoDB, the parameters passed in the header differ from other templates." + }, + { + "id": "b43b9abb-dde7-4389-880e-38ef995d501a", + "title": "Eventbridge Custom Error Function", + "snippet": "/eventbridgeErrorFunction.js", + "description": "Example of a custom error function, which takes in the error and changeEvent as arguments." + } + ] +} diff --git a/snippets/functions/boilerplate/scheduledTrigger.js b/snippets/functions/boilerplate/scheduledTrigger.js new file mode 100644 index 0000000..df4d635 --- /dev/null +++ b/snippets/functions/boilerplate/scheduledTrigger.js @@ -0,0 +1,21 @@ +exports = async function () { + // A Scheduled Trigger will always call a function without arguments. + // Documentation on Triggers: https://www.mongodb.com/docs/atlas/app-services/triggers/ + + // Functions run by Triggers are run as System users and have full access to Services, Functions, and MongoDB Data. + + // Get the MongoDB service you want to use (see "Linked Data Sources" tab) + const serviceName = "mongodb-atlas"; + const databaseName = "db_name"; + const collectionName = "coll_name"; + const collection = context.services + .get(serviceName) + .db(databaseName) + .collection(collectionName); + + try { + const doc = await collection.findOne({ name: "mongodb" }); + } catch (err) { + console.log("error performing mongodb findOne: ", err.message); + } +};