UNPKG

transactions-mongoose

Version:
193 lines (148 loc) β€’ 6.77 kB
# πŸ‡ΊπŸ‡¦ Transactions for mongoose [![os, nodes](https://github.com/rosbitskyy/transactions-mongoose/actions/workflows/push-main.yml/badge.svg)](https://github.com/rosbitskyy/transactions-mongoose/actions) [![npm version](https://img.shields.io/npm/v/transactions-mongoose.svg)](https://www.npmjs.com/package/transactions-mongoose) [![Downloads/month](https://img.shields.io/npm/dm/transactions-mongoose.svg)](http://www.npmtrends.com/transactions-mongoose) [![Vulnerabilities](https://snyk.io/test/npm/transactions-mongoose/badge.svg)](https://snyk.io/test/npm/transactions-mongoose) **Transactions allow you to perform multiple group operations in isolation and undo all operations if one of them fails.** This module allows you to combine different transactions and operations into a group and execute them together. Pre-checks the schema for errors, duplication of unique indexes/fields Very simple and extremely easy β˜•οΈ : - A couple of methods for everything - Mix executors as you like - Use the session for your usual, standard saving And yes, let's start! β˜•οΈ [buy me a coffee](https://www.buymeacoffee.com/rosbitskyy.ruslan) ### Installation First install [Node.js](https://nodejs.org/uk) and [MongoDB](https://www.mongodb.com/try). Then: ```shell npm i transactions-mongoose ``` Mongoose [latest](https://www.npmjs.com/package/transactions-mongoose?activeTab=dependencies) also included ### Usage ```javascript const {Transaction} = require("transactions-mongoose"); const transaction = new Transaction(); // or with debug log const transaction = new Transaction().setSendbox(true); ``` ## An exemplary use case ### [Create / Insert new document](https://github.com/rosbitskyy/transactions-mongoose/blob/main/tests/create-insert.js) ```javascript const {Transaction} = require("transactions-mongoose"); const transaction = new Transaction().setSendbox(true); const transactionData1 = transaction.add({ Person, firstname: 'Sancho', lastname: 'Panse', age: 22, sex: 'male', status: 'free' }); const transactionData2 = transaction.add({ Model: 'Person', firstname: 'Janna', lastname: 'Dark', age: 21, sex: 'female', status: 'free' }); transaction.add(Person, { firstname: 'Hulio', lastname: 'Iglessias', age: 35, sex: 'male', status: 'free' }); await transaction.commit(); console.log('transaction 1 result', transactionData1.result) // the result of the save() operation console.log('transaction 2 document', transactionData2.document) ``` ### [Update an existing one](https://github.com/rosbitskyy/transactions-mongoose/blob/main/tests/update-existing.js) ```javascript const {Transaction} = require("transactions-mongoose"); const transaction = new Transaction().setSendbox(true); // variant #1 - use standard setters let personSancho = await Person.findById('...Sancho id'); personSancho.age += 1; personSancho.status = 'married'; personSancho.friend_id = '...Hulio Iglessias id'; transaction.add(personSancho); // variant #2 - by document and update object let personJanna = await Person.findById('...Janna id'); transaction.add(personJanna).update({ age: ++personJanna.age, status: 'married', friend_id: personSancho._id, bodyFriend_id: '...Hulio Iglessias id', }); // variant #3 - by ObjectId transaction.add(Person, {_id: personSancho._id}).update({ friend_id: personJanna._id }); transaction.add({Person, _id: personSancho._id}).update({ friend_id: personJanna._id }); await transaction.commit(); ``` ### [Executing an isolated block that may fail is not related to Mongo but affects whether the data is saved or not.](https://github.com/rosbitskyy/transactions-mongoose/blob/main/tests/execute.js) ```javascript const fetch = require("node-fetch"); const {Transaction} = require("transactions-mongoose"); const transaction = new Transaction().setSendbox(true); const getAvatar = async (id) => { const response = await fetch('https://i.pravatar.cc/300?u=' + id); const blob = await response.blob() return "data:" + blob.type + ';base64,' + Buffer.from(await blob.arrayBuffer()).toString('base64'); }; const transactionData = transaction.execute(async () => { let personSancho = await Person.findById('...Sancho id'); transaction.add(personSancho).update({ updatedAt: Date.now(), __v: ++personSancho.__v }); // there may be a timeout error or a reader processing error personSancho.avatar = await getAvatar(personSancho._id) transaction.execute(async () => { let personHulio = await Person.findById('...Hulio id'); personHulio.avatar = await getAvatar(personHulio._id); transaction.add(personHulio) }); let personJanna = await Person.findById('...Janna id'); personJanna.avatar = await getAvatar(personJanna._id); const td = transaction.add(personJanna) // The result can be whatever you want // we will return the Janna document update result // https://mongoosejs.com/docs/api/query.html#Query.prototype.updateOne() return td }); // and also execute it :) personJanna.updatedAt = Date.now() transaction.add(personJanna) await transaction.commit(); console.log('transaction result', transactionData.result.result); ``` ### [With session executor](https://github.com/rosbitskyy/transactions-mongoose/blob/main/tests/sessions.js) To use with Mongo Replica set ```javascript const {Transaction} = require("transactions-mongoose"); const transaction = new Transaction().setSendbox(true); transaction.session(async (session) => { let personSancho = await Person.findById('...Sancho id').session(session); let personJanna = await Person.findById('...Janna id').session(session); let personHulio = await Person.findById('...Hulio id').session(session); personSancho.age = 100; // <-- let's try to make it more mature await personSancho.save({session}) personJanna.age = 100; // <-- let's try to make it more mature too await personJanna.save({session}) personHulio.age = 100; // <-- let's try to make it more mature too await personHulio.save({session}) throw new Error('Test an error - or remark me') // No changes will be saved // return result - The result can be whatever you want return personJanna }); await transaction.commit(); ``` If the scheme uses {timestamps: true} in the options, or the fields createdAt (if the document is new), updatedAt (for new and updates) - they will be automatically created or updated updatedAt. [![](https://img.shields.io/badge/mongoose-v5.x.x_and_up-blue?logo=mongoosedotws)](https://www.npmjs.com/package/mongoose) [![](https://img.shields.io/badge/Node.js-v16.x.x_and_up-blue?logo=nodedotjs)](https://nodejs.org)