diff --git a/Week4/assignment/Aggregation/.gitignore b/Week4/assignment/Aggregation/.gitignore new file mode 100644 index 000000000..e78bbd2a3 --- /dev/null +++ b/Week4/assignment/Aggregation/.gitignore @@ -0,0 +1,20 @@ +# Node modules +node_modules/ + +# Logs +*.log + +# Environment variables +.env + +# Build output +dist/ +build/ + +# OS files +.DS_Store +Thumbs.db + +# IDE files +.vscode/ +.idea/ diff --git a/Week4/assignment/Aggregation/ex1-aggregation.js b/Week4/assignment/Aggregation/ex1-aggregation.js new file mode 100644 index 000000000..ff7546c6c --- /dev/null +++ b/Week4/assignment/Aggregation/ex1-aggregation.js @@ -0,0 +1,94 @@ +import { MongoClient } from "mongodb"; +import dotenv from "dotenv" + +dotenv.config() + +const url = process.env.MONGODB_URL +if(!url) throw new Error("MONGODB_URL is not set in .env") +const client = new MongoClient(url); +const db = client.db("databaseWeek4"); +const collection = db.collection("week4Exercises"); + + /*Write a function that will return the array of the total population (M + F over all age groups) for a given Country per year. + The result should look something like this, these are the values for Netherlands:*/ + +async function getTotalPopulationByCountryPerYear() { + try { + // Example query: find first 1 document + const docs = await collection.find().limit(1).toArray(); + console.log(docs); + + const pipeline = [ + { $match: { Country: "Netherlands" } }, + { + $group: { + _id: "$Year", + countPopulation: { $sum: { $add: ["$M", "$F"] } }, + }, + }, + { $sort: { _id: 1 } }, + ]; + + const result = await collection.aggregate(pipeline).toArray(); + console.log(result); + + const formated = result.map((item) => { + return { + Year: item._id, + countPopulation: item.countPopulation, + }; + }); + console.table(formated); + } catch (err) { + console.error(err); + } +} + +/*Write a function that will return all the information of each continent for a given Year +and Age field but add a new field TotalPopulation that will be the addition of M and F. +For example, if I would give 2020 for the Year and 100+ for the Age it should return something like this:*/ +async function getContinentPopulation(year, age) { + try { + const continents = [ + "AFRICA", + "ASIA", + "EUROPE", + "LATIN AMERICA AND THE CARIBBEAN", + "NORTHERN AMERICA", + "OCEANIA", + ]; + const pipeline = [ + { + $match: { Year: year, Age: age, Country: { $in: continents } }, + }, + { + $addFields: { + TotalPopulation: { $add: ["$M", "$F"] }, + }, + }, + ]; + + const result = await collection.aggregate(pipeline).toArray(); + return result; + } catch (error) { + console.error("Error", error); + } +} + +async function main() { + try { + await client.connect(); + console.log("Connected to local MongoDB"); + await getTotalPopulationByCountryPerYear(); + + const data = await getContinentPopulation(2020, "100+"); + console.log(data); + console.table(data); + } catch (err) { + console.error(err); + } finally { + await client.close(); + } +} + +main(); diff --git a/Week4/assignment/Aggregation/package-lock.json b/Week4/assignment/Aggregation/package-lock.json new file mode 100644 index 000000000..812697bd7 --- /dev/null +++ b/Week4/assignment/Aggregation/package-lock.json @@ -0,0 +1,176 @@ +{ + "name": "aggregation", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "aggregation", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^17.2.2", + "mongodb": "^6.19.0" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.0.tgz", + "integrity": "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/bson": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/dotenv": { + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", + "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, + "node_modules/mongodb": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.19.0.tgz", + "integrity": "sha512-H3GtYujOJdeKIMLKBT9PwlDhGrQfplABNF1G904w6r5ZXKWyv77aB0X9B+rhmaAwjtllHzaEkvi9mkGVZxs2Bw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/Week4/assignment/Aggregation/package.json b/Week4/assignment/Aggregation/package.json new file mode 100644 index 000000000..522dd063a --- /dev/null +++ b/Week4/assignment/Aggregation/package.json @@ -0,0 +1,18 @@ +{ + "name": "aggregation", + "version": "1.0.0", + "description": "", + "main": "ex1-aggregation.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node ex1-aggregation.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "dotenv": "^17.2.2", + "mongodb": "^6.19.0" + } +} diff --git a/Week4/assignment/Transaction/.gitignore b/Week4/assignment/Transaction/.gitignore new file mode 100644 index 000000000..7fdb8c7cd --- /dev/null +++ b/Week4/assignment/Transaction/.gitignore @@ -0,0 +1,20 @@ +# Node modules +node_modules/ + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment variables +.env + +# OS files +.DS_Store +Thumbs.db + +# Optional: Build output +dist/ +build/ diff --git a/Week4/assignment/Transaction/db.js b/Week4/assignment/Transaction/db.js new file mode 100644 index 000000000..ee78bc9d3 --- /dev/null +++ b/Week4/assignment/Transaction/db.js @@ -0,0 +1,12 @@ +import { MongoClient } from "mongodb"; +import dotenv from "dotenv"; + +dotenv.config(); + +const MONGODB_URL = process.env.MONGODB_URL; +if (!MONGODB_URL) throw new Error("MONGODB_URL is not defined in .env"); +const client = new MongoClient(MONGODB_URL); +const db = client.db("Transfer"); +const transactionsCollection = db.collection("transactions"); + +export { client, transactionsCollection }; diff --git a/Week4/assignment/Transaction/index.js b/Week4/assignment/Transaction/index.js new file mode 100644 index 000000000..3d37e9b82 --- /dev/null +++ b/Week4/assignment/Transaction/index.js @@ -0,0 +1,20 @@ +import { client } from "./db.js"; +import { createAccounts, showAccounts } from "./setup.js"; +import { transferMoney } from "./transfer.js"; + +async function connectToDatabase() { + try { + await client.connect(); + console.log(`Successfully connected to MongoDB`); + await createAccounts(); + await showAccounts(); + await transferMoney(102, 103, 900); + await showAccounts(); + } catch (error) { + console.error("Error:", error); + } finally { + await client.close(); + } +} + +connectToDatabase(); diff --git a/Week4/assignment/Transaction/package-lock.json b/Week4/assignment/Transaction/package-lock.json new file mode 100644 index 000000000..75f23932f --- /dev/null +++ b/Week4/assignment/Transaction/package-lock.json @@ -0,0 +1,176 @@ +{ + "name": "transaction", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "transaction", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^17.2.2", + "mongodb": "^6.19.0" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.0.tgz", + "integrity": "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/bson": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/dotenv": { + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", + "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, + "node_modules/mongodb": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.19.0.tgz", + "integrity": "sha512-H3GtYujOJdeKIMLKBT9PwlDhGrQfplABNF1G904w6r5ZXKWyv77aB0X9B+rhmaAwjtllHzaEkvi9mkGVZxs2Bw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/Week4/assignment/Transaction/package.json b/Week4/assignment/Transaction/package.json new file mode 100644 index 000000000..594583b14 --- /dev/null +++ b/Week4/assignment/Transaction/package.json @@ -0,0 +1,18 @@ +{ + "name": "transaction", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "dotenv": "^17.2.2", + "mongodb": "^6.19.0" + } +} diff --git a/Week4/assignment/Transaction/setup.js b/Week4/assignment/Transaction/setup.js new file mode 100644 index 000000000..53457d4bd --- /dev/null +++ b/Week4/assignment/Transaction/setup.js @@ -0,0 +1,34 @@ +import { transactionsCollection } from "./db.js"; +export async function createAccounts() { + try { + await transactionsCollection.deleteMany({}); + const accounts = [ + { + account_number: 102, + balance: 5000, + account_changes: [], + }, + { + account_number: 103, + balance: 10000, + account_changes: [], + }, + ]; + + const result = await transactionsCollection.insertMany(accounts); + + console.log(`Inserted ${result.insertedCount} accounts`); + return result; + } catch (error) { + console.error("Error creating accounts:", error); + } +} + +export async function showAccounts() { + try { + const result = await transactionsCollection.find({}).toArray(); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error("Error showing accounts:", error); + } +} diff --git a/Week4/assignment/Transaction/transfer.js b/Week4/assignment/Transaction/transfer.js new file mode 100644 index 000000000..6f59b8ffc --- /dev/null +++ b/Week4/assignment/Transaction/transfer.js @@ -0,0 +1,65 @@ +import { client, transactionsCollection } from "./db.js"; + +export async function transferMoney(fromAccount, toAccount, amount) { + const sender = await transactionsCollection.findOne({ + account_number: fromAccount, + }); + const receiver = await transactionsCollection.findOne({ + account_number: toAccount, + }); + + if (!sender || !receiver) + throw new Error("One of the accounts does not exist"); + if (sender.balance < amount) throw new Error("Insufficient funds"); + + const senderChangeNumber = + (sender.account_changes.at(-1)?.change_number ?? 0) + 1; + const receiverChangeNumber = + (receiver.account_changes.at(-1)?.change_number ?? 0) + 1; + + const remark = `Transferred ${amount} from account ${fromAccount} to account ${toAccount}`; + + const session = client.startSession(); + try { + await session.withTransaction(async () => { + await transactionsCollection.updateOne( + { account_number: fromAccount }, + { + $inc: { balance: -amount }, + $push: { + account_changes: { + change_number: senderChangeNumber, + amount: -amount, + changed_date: new Date(), + remark, + }, + }, + }, + { session } + ); + + await transactionsCollection.updateOne( + { account_number: toAccount }, + { + $inc: { balance: amount }, + $push: { + account_changes: { + change_number: receiverChangeNumber, + amount: amount, + changed_date: new Date(), + remark, + }, + }, + }, + { session } + ); + }); + + console.log(remark); + } catch (error) { + console.error(" Transaction failed:", error.message); + await session.abortTransaction(); + } finally { + await session.endSession(); + } +}