Skip to content
Open
100 changes: 100 additions & 0 deletions Week4/homework/ex1-aggregation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { MongoClient } from "mongodb";
import "dotenv/config";
const clientMongo = new MongoClient(process.env.MONGODB_URL);
import fs from "fs";
import csv from "csv-parser";
let data;

async function processCSV(fileName) {
return new Promise((resolve, reject) => {
const data = [];
fs.createReadStream(fileName)
.pipe(csv())
.on("data", (row) => data.push(row))
.on("end", () => resolve(data))
.on("error", (err) => reject(err));
});
}

async function getTotalPopulationByYear(collection, country) {
const result = await collection
.aggregate([
{ $match: { Country: country } },
{
$group: {
_id: { $toInt: "$Year" },
countPopulation: {
$sum: {
$add: [{ $toInt: "$M" }, { $toInt: "$F" }],
},
},
},
},
{ $sort: { _id: 1 } },
])
.toArray();
return result;
}

async function getContinentsPopulation(collection, year, age) {
const result = await collection
.aggregate([
{
$match: {
Year: year.toString(),
Age: age.toString(),
// Filter only continents by checking if Country is uppercase
$expr: {
$eq: ["$Country", { $toUpper: "$Country" }],
},
},
},
{
$addFields: {
TotalPopulation: { $add: [{ $toInt: "$M" }, { $toInt: "$F" }] },
},
},
{
$project: {
_id: 1,
Country: 1,
Year: 1,
Age: 1,
M: 1,
F: 1,
TotalPopulation: 1,
},
},
])
.toArray();
return result;
}

async function main() {
try {
await clientMongo.connect();
const db = clientMongo.db("databaseWeek4");
const collection = db.collection("population_pyramid");
data = await processCSV(
"./Week4/homework/ex1-aggregation/population_pyramid_1950-2022.csv"
);
await collection.insertMany(data);
data = await getTotalPopulationByYear(collection, "Netherlands");
console.log(
"\nPopulation by Year (Netherlands):\n",
JSON.stringify(data, null, 2)
);
data = await getContinentsPopulation(collection, "2020", "100+");
console.log(
"\nPopulation by Continent (2020, 100+):\n",
JSON.stringify(data, null, 2)
);
} catch (error) {
console.error("Error connecting to MongoDB:", error);
} finally {
await clientMongo.close();
console.log("Connection to MongoDB closed");
}
}

main();
41 changes: 41 additions & 0 deletions Week4/homework/ex2-transactions/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"accounts": [
{ "account_number": 101, "balance": 5000 },
{ "account_number": 102, "balance": 12000 },
{ "account_number": 103, "balance": 7500 },
{ "account_number": 104, "balance": 3000 },
{ "account_number": 105, "balance": 9500 }
],
"account_changes": [
{
"account_number": 101,
"amount": 1000,
"changed_date": "2025-09-01",
"remark": "Salary deposit"
},
{
"account_number": 102,
"amount": -500,
"changed_date": "2025-09-02",
"remark": "Grocery shopping"
},
{
"account_number": 103,
"amount": 2000,
"changed_date": "2025-09-03",
"remark": "Freelance payment"
},
{
"account_number": 104,
"amount": -1000,
"changed_date": "2025-09-04",
"remark": "Rent payment"
},
{
"account_number": 105,
"amount": 1500,
"changed_date": "2025-09-05",
"remark": "Gift received"
}
]
}
23 changes: 23 additions & 0 deletions Week4/homework/ex2-transactions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { setup } from "./setup.js";
import { transfer } from "./transfer.js";
let clientMongo, account;
async function main() {
try {
({ clientMongo, account } = await setup());
const transactionDetails = {
donator_account_number: 101,
receiver_account_number: 102,
amount: 1000,
changed_date: new Date().toISOString().slice(0, 10), // 'YYYY-MM-DD'
remark: `Transfer from 101 to 102`,
};
await transfer(clientMongo, account, transactionDetails);
} catch (error) {
console.error("Error:", error);
} finally {
await clientMongo.close();
console.log("Connection to MongoDB closed");
}
}

main();
24 changes: 24 additions & 0 deletions Week4/homework/ex2-transactions/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MongoClient } from "mongodb";
import "dotenv/config";
import fs from "fs";

export async function setup() {
const { accounts, account_changes } = JSON.parse(
fs.readFileSync("./Week4/homework/ex2-transactions/data.json")
);
const clientMongo = new MongoClient(process.env.MONGODB_URL);
await clientMongo.connect();
const db = clientMongo.db("databaseWeek4");
const account = await db.createCollection("accounts");
await account.deleteMany({});
for (const acc of accounts) {
acc.account_changes = account_changes
.filter((a) => a.account_number === acc.account_number)
.map((a) => {
delete a.account_number;
return a;
});
await account.insertOne(acc);
}
return { clientMongo, account };
}
48 changes: 48 additions & 0 deletions Week4/homework/ex2-transactions/transaction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Client } from "pg";
const config = {
host: "localhost",
user: "hyfuser",
password: "hyfpassword",
database: "transactions_week3",
port: 5432,
};
const client = new Client(config);

async function seedDatabase(client) {
try {
await client.connect();
console.log("Connected to PostgreSQL database!");

const donator_account_number = 101;
const receiver_account_number = 102;
const amount = 1000;
const changed_date = new Date().toISOString().slice(0, 10); // 'YYYY-MM-DD'
const remark = `Transfer from 101 to 102`;

await client.query("BEGIN");
await client.query(
"UPDATE ACCOUNT SET balance = balance - $1 WHERE account_number = $2",
[amount, donator_account_number]
);
await client.query(
"UPDATE ACCOUNT SET balance = balance + $1 WHERE account_number = $2",
[amount, receiver_account_number]
);
await client.query(
"INSERT INTO account_changes(account_number, amount, changed_date, remark) VALUES($1, $2, $3, $4)",
[donator_account_number, -amount, changed_date, remark]
);
await client.query(
"INSERT INTO account_changes(account_number, amount, changed_date, remark) VALUES($1, $2, $3, $4)",
[receiver_account_number, amount, changed_date, remark]
);
await client.query("COMMIT");
console.log("Transaction completed!");
} catch (error) {
console.error("Error seeding database:", error);
} finally {
await client.end();
}
}

seedDatabase(client);
42 changes: 42 additions & 0 deletions Week4/homework/ex2-transactions/transfer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export async function transfer(clientMongo, account, transactionDetails) {
const {
donator_account_number,
receiver_account_number,
amount,
changed_date,
remark,
} = transactionDetails;
const session = clientMongo.startSession();
const transactionOptions = {
readPreference: "primary",
readConcern: { level: "local" },
writeConcern: { w: "majority" },
};
try {
await session.withTransaction(async () => {
await account.updateOne(
{ account_number: donator_account_number },
{
$inc: { balance: -amount },
$push: { account_changes: { amount: -amount, changed_date, remark } },
},
{ session }
);
await account.updateOne(
{ account_number: receiver_account_number },
{
$inc: { balance: amount },
$push: { account_changes: { amount: amount, changed_date, remark } },
},
{ session }
);
}, transactionOptions);
console.log("Transaction committed.");
} catch (error) {
console.log("Transaction aborted.", error);
Comment on lines +35 to +36

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: It's ok in the assignment to use simple error handling (just logging). In real working situation, usually the error will be thrown or return some thing that clearly differentiates the normal state without error.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

throw new Error(error);
} finally {
await session.endSession();
console.log("Transaction completed!");
}
}
Loading