包 Lecture 0 至 5、Lab 01 至 04,同 w2 至 w4 嘅 question set(2026 Autumn)。 Slide 寫住 Not Examined 嘅嘢,呢度會標 (NE) 或者直接唔寫。
Lab exercise 01(hands-on test)
| 項目 | 詳情 |
|---|---|
| 範圍 | Week 1 至 4 嘅嘢。Open-book |
| 堂上部分(40 分) | Task 1 + 2,喺你自己嗰堂 tutorial 做(29 Sep 至 5 Oct),唔可以去其他組嗰堂。題目會早一日放上 OLE(Week 5 block)。做完俾 examiner 一次過睇結果,睇完就可以走 |
| 堂後部分(60 分) | Task 3(mongosh 實際操作)+ Task 4(短答題) |
| 交功課 | 一個 PDF,名叫 your-8-digit-SID_exe01.pdf,交上 OLE,死線 23:59, Mon 12 Oct 2026。截止嗰日唔可以再交過,所以最好早一日交。第一頁寫名同 SID |
| Screenshot | 要影成個 screen,包埋 taskbar 嘅日期同時間,唔好淨係影 terminal 個窗。影唔齊或者影唔晒會扣分 |
| 規矩 | 抄襲、或者成份都係 AI/agent 做嘅,一律 0 分。呢頁係溫書筆記,冇答案 |
實戰練習
練到唔使睇任何嘢,都識喺 mongosh 做晒以下呢啲:
- 喺 Atlas 搵到 connection string,用
mongosh連上去(database user + 密碼,特殊符號要 URL encode) - 用
use <db>開/轉 database,用db.createCollection("<name>")開 collection - 用
insertMany([...])放入有 array、nested object 同數字嘅 document(字串加引號,數字唔使) - 用
find()配比較 operator($gt、$lt、$in),同用 dot notation 搵 nested field - 用
updateMany()配$set/$push/$pull/$pop改 array field - 識分
deleteOne()同deleteMany(),同埋點樣加 filter - 用淺白嘅說話講到 JSON、MongoDB、JavaScript 同 Node.js 之間嘅關係,同埋點解 async 對 server 咁重要(睇下面第 2 至 4 節)
0. 課程安排
| 項目 | 詳情 |
|---|---|
| Coordinator | Dr. LIU Alin(ylliu@hkmu.edu.hk)。成科嘅問題搵佢 |
| OCAS 50% | 兩次 lab exercise 佔 30%(大約 week 5 同 8,有筆試有 coding,open-book)。Group project 佔 20%(4 至 6 人一組,week 12 至 13):project files 10% + presentation 10% |
| Final exam 50% | 面對面、closed book、「會俾啲 hint」。考晒所有嘢(NE 除外),有文字題同 coding 知識 |
| 合格線 | OCAS 同考試兩樣都要攞到 C(大約 50 分)。最低 D(大約 40 分) |
| Bonus | 堂上答 bonus question 答啱會加落 OCAS。出席本身唔計分,但你要喺度先有機會攞 bonus |
| 考試 tip | MongoDB command 唔使死背。要明白佢哋做咩、識得用,因為考試會俾 hint |
課程內容(跟次序):工具(Linux、Git、NoSQL、server-side scripting、MVC),framework(SOA、REST、API),virtualisation,最後係 cloud computing(概念、服務、收費模式、deployment)。
1. 基本概念同工具(Lecture 1、Lab 01)
Client-server model
- Server 係一部或者多部電腦,負責提供 network service。Client(用家部機)就負責要求呢啲 service。
- Network service 即係:提供內容(網頁、檔案),同分享資源(程式、數據、儲存空間)。
- (NE) 好處:可以集中 backup、安全、效能好、易 scale。壞處:塞車(traffic congestion)、server 一死就全部用唔到(唔 robust)、可能要特別嘅 hardware。
Server-side app 做四樣嘢
- Query 同處理 database
- 讀寫 server 上面嘅檔案
- 同其他 server 溝通,處理用家輸入
- 組織成一個 web application
Cloud
- Cloud:由第三方公司營運嘅遙遠 data centre 或者平台(IBM、AWS、Heroku、Render、Huawei)。
- Cloud computing:隨叫隨用嘅電腦資源(特別係儲存空間同計算能力),用家唔使自己親手管理。有彈性、隨時用得。
- Cloud server app 即係 deploy 咗上 cloud 嘅 server-side app。好處:快啲回應業務需要、操作簡單啲、即刻 scale 到、可以用 API、平啲。
主要 server-side 技術(成科嘅路線圖)
| 範疇 | 技術 | 一句講晒 |
|---|---|---|
| Database 管理 | NoSQL、JSON、MongoDB | 儲大量冇固定結構嘅數據。JSON 即係將 JS object 寫成文字。MongoDB 係雲端 document database |
| Server-side 編程 | Node.js | 喺 server 行 JavaScript 嘅 runtime,用嚟生成動態內容 |
| Data/Object mapping | Mongoose(ODM) | Object Data Modelling library,將 code 入面嘅 object 同 MongoDB document 互相轉換 |
| 將網頁送俾 client | Express.js | 輕巧、靈活嘅 Node.js web framework(server-side MVC) |
| 身份識別 | Session、Middleware、OAuth | Session:將好多個 request 認做同一個用家。Middleware:改 req/res object。OAuth:用 token 做授權嘅開放標準 |
| 整合服務 | API(SOAP、REST、GraphQL) | 俾一個系統用到另一個系統嘅數據或者功能 |
開發工具
- Platform virtualisation software(emulator/hypervisor)會模擬一部實體電腦,通常一部機可以行幾部 VM。呢科用 VirtualBox(或者 VMware Workstation)行 Ubuntu 22.04。VM 入面整死咗都唔會搞壞你部真機。
- Ubuntu 係 Debian-based 嘅 Linux。適合做開發,因為喺 terminal 裝軟件、管理軟件好快,而且社群大、工具多。
- GitHub 係一個平台,俾你開、儲、管理同分享 code。
真係會用到嘅 Ubuntu command
| Command | 意思 |
|---|---|
cd ~ / cd path | 返 home/轉去另一個 folder |
pwd | 顯示而家喺邊個 folder |
ls | 列出檔案 |
mkdir name | 開新 folder |
gedit file | 用 editor 開新檔或者打開檔案 |
rm -rf name | 刪檔案/folder(連入面嘅嘢、唔問你) |
cp、mv、touch、cat、grep、sudo、chmod、chown、tar、ps、top、df、du | 「25 個基本 command」其餘嗰啲 |
行一個 Node app
# 將老師啲 code 成份搬返屋企
git clone https://github.com/yalin-liu/cloudserver-2026.git
# 行入 helloworld 間房
cd ~/cloudserver-2026/lab01/helloworld
# 睇住張購物單,買齊所有材料
npm install
# 開舖!叫 server 起身做嘢
npm start
# 開 browser 去 localhost:8099 睇;撳 Ctrl+C 就收舖
package.json 嘅 field
| Field | 用途 |
|---|---|
name、description、author、version | app 嘅基本資料 |
dependencies | 要裝嘅 node module,例如 "express": "*"、"mongodb": "6.9.0" |
engine | 要用邊個版本嘅 Node.js,例如 "node >= 10.0.0" |
scripts | shell command;"start": "node server" 會喺 npm start 時行 |
helloworld 嘅 server.js(Express)
// 攞 express 呢件工具出嚟
const express = require('express')
// 用佢砌一間舖仔
const app = express()
// 舖仔嘅門牌號碼,冇人話就用 8099
const port = process.env.PORT || 8099
// 有人嚟大門口,就同佢講 Hello World!
app.get('/', (req, res) => { res.send('Hello World!') })
// 開門等客,開到門就講一聲
app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) })
localhost即係你自己部機。Port 就係分清你喺同部機邊個 service 傾偈。
2. NoSQL 同 JSON(Lecture 2)
SQL vs NoSQL
| SQL/RDBMS(1970s 起) | NoSQL(2000s 起) | |
|---|---|---|
| 數據 | 有結構嘅 table,schema 固定 | Schema 有彈性,數據冇固定結構 |
| Mapping | 要用 ORM | 好多唔使 ORM,document 直接對應程式語言嘅數據結構 |
| Transaction | 完整 ACID | 多數放寬 ACID,換取彈性同速度 |
| 弱點/強項 | 處理唔到冇結構或者超大量嘅數據 | Query 快(唔使 join)、開發者易用、易改數據模型 |
| 例子 | Oracle、MySQL、SQL Server | MongoDB(document)等等 |
- 點解要 NoSQL:儲存變平咗、數據量多咗,而且數據乜形狀都有。
- ACID:Atomicity(要就全部做,唔係就全部唔做)、Consistency(永遠由一個合法狀態去另一個合法狀態)、Isolation(同時做都好似逐個做咁)、Durability(commit 咗就一定喺度)。
- NoSQL 四大類:Document(JSON document)· Key-value · Wide-column(每行 column 可以唔同)· Graph(node 同 edge)。
JSON
- JavaScript Object Notation:輕量、純文字、唔限語言嘅數據交換格式,易讀易寫。副檔名
.json,media typeapplication/json(RFC 4627)。 - 由兩種結構組成:
- Object
{ }:冇次序嘅 name/value pair。Name 一定係雙引號字串,後面跟:;每對之間用,分隔。 - Array
[ ]:有次序嘅一串 value。
- Object
- Value 有 6 種:string · number · object · array · boolean · null。
{ } [ ] : ,前後有冇空格都冇所謂。
3. MongoDB(Lecture 2 同 3、Lab 02 同 03)
概念
| MongoDB | SQL 對應 |
|---|---|
| Database | Database |
| Collection | Table |
| Document(field-value pair,用 BSON 即 binary JSON 儲) | Row/record |
| Field | Column |
- 每份 document 都有獨一無二嘅
_id(primary key)。你唔俾,MongoDB 會自動生成一個ObjectId。 - Dynamic schema:同一個 collection 入面嘅 document 可以有唔同 field,同一個 field 都可以擺唔同 type。
- 一個 server 有好多個 database,每個 database 有好多個 collection,而每個 collection 只會屬於一個 database。
Atlas 設定清單(Lab 02 B-1)
- 開 Atlas 戶口(登入 email + 密碼)。
- 起一個免費 cluster(揀 Azure、auto security、load sample dataset)。記低 cluster 名,例如
Cluster0。 - 開一個 database user,設密碼,role 揀 Atlas admin。呢個唔係你登入 Atlas 網站嗰個戶口。
- Whitelist IP
0.0.0.0/0(俾任何 IP 連)。Whitelist 係限制邊啲機連得入嚟;lab 全開,因為 lab 啲網絡成日變。 - Load sample DB(
sample_restaurants.restaurants周圍都用到)。
連線
- 三種方法:mongosh(shell,呢科用呢個)、Robo 3T(GUI,NE),或者 Node.js app(用 driver)。
- 喺
Cluster0 > Connect > Shell攞 command。用mongosh --version睇版本。密碼有特殊符號一定要 URL encode。 - 見到
[primary] test>就即係連咗 cluster 嘅 primary node,而家用緊testdatabase。
Shell 速查
// 睇下有幾多個大玩具箱
show dbs
// 揀一個玩具箱嚟玩(冇就開個新嘅)
use sample_restaurants
// 將手上個玩具箱成個掉咗(小心!)
db.dropDatabase()
// 睇下箱入面有幾多個小盒
show collections
// 整多個新小盒
db.createCollection("mycollection")
// 將呢個小盒連玩具一齊掉咗
db.mycollection.drop()
// 講拜拜,走
exit
CRUD
// CREATE = 放嘢入去。冇盒會自動整盒,冇名牌(_id)會自動貼
// 放一張卡仔入盒
db.inventory.insertOne({ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } })
// 一次放好多張卡仔,用 [ ] 捧住
db.inventory.insertMany([{...}, {...}])
// 日子:Date() = 而家;想寫指定日子就用 new Date("2014-10-01")
// READ = 搵嘢。第一個 {} 講搵咩,第二個 {} 講睇邊啲
// 全部卡仔攞晒出嚟
db.restaurants.find()
// 兩樣都要啱先要
db.restaurants.find({ borough: "Manhattan", cuisine: "Italian" })
// $or:啱其中一樣就要
db.restaurants.find({ $or: [{ cuisine: "Italian" }, { cuisine: "American" }] })
// $in:喺張名單入面就要(同上面一樣,短啲)
db.restaurants.find({ cuisine: { $in: ["Italian", "American"] } })
// $nor:唔係意大利菜先要
db.restaurants.find({ $nor: [{ cuisine: "Italian" }] })
// 盒入面仲有細盒?用「.」行入去,要加引號
db.inventory.find({ "size.uom": "in" })
// 幾樣一齊要啱:h 細過 15、uom 係 in、status 係 D
db.inventory.find({ "size.h": { $lt: 15 }, "size.uom": "in", status: "D" })
// 「.0」即係串珠仔第一粒
db.c.find({ "memos.0.by": "shipping" })
// 串珠仔入面,有一粒啱就要
db.restaurants.find({ grades: { $elemMatch: { score: { $gt: 10 } } } })
// 1 = 俾我睇,0 = 收埋佢;名牌 _id 唔講就會出
db.restaurants.find({}, { name: 1, borough: 1, _id: 0 })
// 乜都俾我睇,淨係收埋 coord
db.restaurants.find({}, { "address.coord": 0 })
// 串珠仔入面,只俾我睇第一粒啱嘅
db.schools.find({ zipcode: "63109" }, { students: { $elemMatch: { school: 102 } } })
// UPDATE = 改嘢。第一個 {} 搵邊張,第二個 {} 點改
// $set:將卡仔上面一樣嘢改咗(冇就寫上去)
db.restaurants.updateOne({ restaurant_id: "30112340" }, { $set: { "address.street": "East 31st Street" } })
// 空 {} = 每一張卡仔都改
db.c.updateMany({}, { $set: { status: "active" } })
// $push:喺串珠仔最尾加多粒
db.restaurants.updateOne({ restaurant_id: "41704620" },
{ $push: { grades: { date: new Date("2015-09-09"), grade: "A", score: 15 } } })
// $pop:1 = 拎走最尾粒,-1 = 拎走最頭粒
db.students.updateOne({ _id: 10 }, { $pop: { scores: 1 } })
// $pull:串珠仔入面,一樣嘅珠全部拎走
// DELETE = 掉嘢
// 掉一張啱嘅卡仔
db.restaurants.deleteOne({ restaurant_id: "30112340" })
// 啱嘅卡仔全部掉晒;空 {} 就連晒全部掉
db.restaurants.deleteMany({ ... })
Query operator:
| 比較 | 邏輯 | ||
|---|---|---|---|
$eq $ne | 等於/唔等於 | $and(用 , 隔開已經係) | 全部啱 |
$gt $gte | 大過/大過或等於 | $or | 其中一個啱 |
$lt $lte | 細過/細過或等於 | $nor | 全部都唔啱 |
$in $nin | 喺/唔喺 array 入面 | $not | 反轉條件 |
要識嘅 update operator:$set(改或者加 field)· $push(加入 array 最尾)· $pull(刪走符合嘅元素)· $pop(刪最頭或者最尾)。
(NE) Regex:/str/ 包含 · /^str/ 開頭係 · /str$/ 結尾係。仲有 .sort()、.limit()、.skip()。
Aggregation
db.collection.aggregate(<pipeline>, <options>) 將好多份 document 計成結果(分組、統計、睇趨勢)。Pipeline 係一串 stage;除非有 $merge 或者 $out,否則唔會改到 collection 入面嘅嘢。
| Stage | 做咩 |
|---|---|
$match | 篩 document(好似 find) |
$group | 按 _id: "$field" 分組,用 accumulator 計數:$sum、$avg、$max |
$unwind | 拆開 array:每粒元素變一份 document |
$project/add fields | 改形狀/加計出嚟嘅 field |
// 同一種菜擺埋一堆,數下每堆有幾多間
db.restaurants.aggregate([{ $group: { _id: "$cuisine", count: { $sum: 1 } } }])
// 用地區 + 菜式分堆,數下每堆有幾多間
db.restaurants.aggregate([{ $group: { _id: { borough: "$borough", cuisine: "$cuisine" }, count: { $sum: 1 } } }])
// 計每間餐廳平均幾多分,淨係留大過 10 分嘅
db.restaurants.aggregate([
// $unwind:將串珠仔拆開,一粒變一張卡
{ $unwind: "$grades" },
// $group:同一間餐廳擺埋一堆,計平均分
{ $group: { _id: "$name", avg_score: { $avg: "$grades.score" } } },
// $match:分完堆先篩,大過 10 分先留
{ $match: { avg_score: { $gt: 10 } } }
])
// 先揀中碼,再同名嘅擺埋一堆,加埋有幾多件
db.orders.aggregate([{ $match: { size: "medium" } },
{ $group: { _id: "$name", totalQuantity: { $sum: "$quantity" } } }])
"$cuisine"個$即係「攞 cuisine 呢個 field 嘅值」。冇$就只係一條普通字串。
Projection vs aggregation:projection 係喺 document 度揀 field 出嚟;aggregation 係將好多份 document 處理同轉換成統計結果。
Data modelling
表示數據之間關係有兩種方法:
| References | Embedded documents | |
|---|---|---|
| 點做 | 喺一份 document 度儲另一份嘅 link/ID,由 app 自己去搵返 | 將相關數據直接擺入同一份 document(sub-document field 或者 array) |
| 模型 | Normalised | Denormalised |
| 適合 | 避免重複(例如 publisher document 儲 books: [id1, id2],唔使每本書都抄一次 publisher) | 一次過讀/改晒相關數據(例如 user 有個 addresses: [...] array,或者 contact + access 兩個 sub-doc) |
4. Node.js 同 async programming(Lecture 4、Lab 04)
點解要 Node.js
- Blocking I/O 問題:傳統 server 每個 thread 都要等每次 I/O(disk、network、DB)做完,好似侍應企喺度乾等廚房煮好先做嘢。結果係 stack overhead、記憶體唔夠用,同埋嘥時間。
- I/O 即係程式同 disk 同 network 嘅互動(讀寫檔案、HTTP request、同 database 傾偈)。比起 RAM 同 CPU 慢好多。每個去 server 嘅 request 都係一次 I/O。
- Node.js(Ryan Dahl,2009)= Chrome V8 engine + event library(libev)。係一個喺 server 行 JavaScript 嘅 runtime environment,行 non-blocking app、生成動態網頁內容。
- 特性:event-driven、single-threaded、non-blocking、asynchronous,所以慳記憶體,一個 thread 就處理到好多同時嚟嘅 request。
- Event loop:唯一嘅主 thread,有 event 發生(有人連入嚟、I/O 做完、timeout)就行對應嘅 callback/async function。Callback 一定要快,因為其他嘢都排緊隊等。
- 流程(餐廳比喻):落 order,交俾 OS(即係「廚房」)連埋一個 callback。唔好等,即刻去接下一張 order。嘢煮好 callback 就會自己彈出嚟。
- 好處:適合要同時搞好多 process、server、service,同大量連線(DB、cache、檔案系統)嘅 app。壞處:唔啱長時間、用 CPU 好重嘅計算,因為得一條 thread 會塞死。解決:小心安排,或者將嗰啲工作搬去第二個 service 做。
nvm/npm
- nvm(Node Version Manager):管理幾個 Node 版本嘅 CLI。用 nvm 裝會一齊有
node同npm。 - npm(Node Package Manager):裝 package。
npm install會讀package.json,所以 clone 落嚟再npm install就砌返成個開發環境。 - Node 檔案就係
.js檔,要行緊先有作用。用node file.js行,唔使 Apache 或者 Tomcat。
Sync vs async
| Synchronous | Asynchronous |
|---|---|
| 一行一行咁行,下一行要等呢行做完 | 唔一定跟次序行,條件啱先行個 function |
| I/O 會 block 住個 thread | I/O 開始咗,程式照做其他嘢,做完由 callback 處理結果 |
JS 本身係 synchronous 同 single-threaded。Async 係由環境提供(browser API、Node 嘅 non-blocking I/O)。
三種 async 寫法
| 寫法 | 年代 | 重點 |
|---|---|---|
| Callback | ES6 之前 | 將一個 function 當參數傳入去,件事做完就 call 佢。簡單、周圍都支援。一層包一層就會變 callback hell/pyramid of doom,error handling 好難搞 |
| Promise (NE 細節) | ES6/ES2015 | 代表一件 async 工作最終成功定失敗。用 .then()/.catch() 串起嚟。util.promisify 可以將 callback API 變 Promise |
| Async/Await | ES2017 | 建基於 Promise。Async code 睇落好似 sync 咁,最易讀 |
Node callback 嘅規矩:error 擺第一個參數,callback 擺最後:
// 教一件要等嘅工作;做完打俾 callback(佢排最後)
function asyncOperation(a, b, c, callback) {
// 出事:第一句就話「出錯呀」
if (/* 出錯 */) return callback(new Error("An error has occurred"))
// 搞掂:第一句話「冇事」(null),跟住俾結果
callback(null, d, e, f)
}
// 叫佢做嘢;做完佢會打返嚟,第一句一定係有冇出錯
asyncOperation(params, function (err, result) { /* 做完先行呢度 */ })
Async 讀檔:先 fs.open(..., cb),再 fs.read(..., cb)。Node 開始咗 I/O 就即刻返去 event loop,數據準備好先行 callback。如果用 fs.readSync 就會 block。
async/await 規則:
asyncfunction 一定會 return 一個 Promise;普通 return 值會自動包成 Promise。await只可以喺 async function 入面用。佢會暫停嗰個 function,等 Promise 有結果,但唔會 block 成個 engine,engine 照處理其他 event。
喺 JS 處理 JSON
// 將一條字變返做一盒嘢
const obj = JSON.parse(text)
// 將一盒嘢變做一條字
const text = JSON.stringify(obj)
// 一粒一粒咁睇串珠仔
for (x in employees) console.log(employees[x].firstName)
Lab 04 weather.js:OpenWeather 俾返嚟嘅係一條字串。JSON.parse(data) 將佢變做 object,之後就讀到入面嘅 nested field:
// 最熱減最凍 = 差幾多度
const tempDifference = jsonObj.main.temp_max - jsonObj.main.temp_min
// 講出東京喺地圖邊個位
console.log(`Tokyo is located at [${jsonObj.coord.lon},${jsonObj.coord.lat}]`)
Lab 04 book.js:books[i].reviews 係一串 object { date: string, score: number }。平均分 = 總分 / reviews.length,記得防 0/0。
5. MongoDB Node.js driver 同 HTTP server(Lecture 5)
Driver 基本架構
安裝:npm install mongodb(或者喺 dependencies 加 "mongodb": "6.9.0",再 npm install)。
// 攞 MongoDB 嘅工具出嚟
const { MongoClient, ServerApiVersion } = require("mongodb")
// 玩具箱嘅地址(喺 Atlas 抄返嚟)
const uri = "<connection string>"
// 準備一個幫你去攞嘢嘅小幫手
const client = new MongoClient(uri)
// 要玩邊個玩具箱
const dbName = "sample_restaurants"
// 要玩箱入面邊個小盒
const collectionName = "restaurants"
// async:入面可以等(await)
async function main() {
// 等小幫手行到玩具箱
await client.connect()
// 到咗就講一聲
console.log("Connected successfully to server")
// 打開玩具箱
const db = client.db(dbName)
// 叫佢去搵餐廳,等佢返嚟
const results = await findRestaurants(db)
// 將搵到嘅嘢印出嚟睇
console.log(JSON.stringify(results))
}
// 開始!出錯就講出錯,最後一定要收拾好
main().then(console.log).catch(console.error).finally(() => client.close())
// .then 成功做、.catch 出錯做、.finally 點都做(唔考寫法,要識意思)
用 driver 做 CRUD(operator 同 shell 一樣,加 await)
// 放一本書入盒
const insertDocument = async (db) => db.collection(collectionName)
.insertOne({ name: "Introduction to Node.js", author: "John Dole", price: 75.00, stock: 0 })
// 放完會話你新卡仔個名牌(insertedId)
// 搵 Manhattan 嘅餐廳,最多 10 間
const findRestaurants = async (db) => db.collection(collectionName)
// 搵到之後要 toArray(),先變成一串俾你
.find({ borough: "Manhattan" }).limit(10).toArray()
// 盒入面搵:.find({ "address.zipcode": "10075" })
// 幫 41156888 嗰間換條街名
const updateRestaurants = async (db) => db.collection(collectionName)
.updateOne({ restaurant_id: "41156888" }, { $set: { "address.street": "East 31st Street" } })
// modifiedCount == 1 即係改咗一張;改好多張用 updateMany
// 掉咗 41156888 嗰間
const deleteRestaurants = async (db) => db.collection(collectionName)
// 想掉好多間就用 deleteMany
.deleteOne({ restaurant_id: "41156888" })
// 行一條流水線
const aggregateRestaurants = async (db) => db.collection(collectionName).aggregate([
// 第一站:淨係留 Queens 嘅巴西菜
{ $match: { borough: "Queens", cuisine: "Brazilian" } },
// 第二站:同一個郵區擺埋一堆,數下有幾多間
{ $group: { _id: "$address.zipcode", count: { $sum: 1 } } }
]).toArray()
HTTP
- HTTP(Hypertext Transfer Protocol)係 request-response protocol:client 送 request,server 回 response。
- Request = request line(
GET /path HTTP/1.1)+ header(多數情況得Host係必須,其他有User-Agent、Accept、Cookie)+ 可有可無嘅 body。 - Response = status line(
HTTP/1.1 200 OK)+ header(Content-Type等等)+ body(例如 HTML)。 - Status code:2xx 成功(200 OK、206 Partial Content)· 3xx redirect · 4xx client 有問題(401 Unauthorized、403 Forbidden、404 Not Found)· 5xx server 有問題。
Slide 寫「505 Internal Server Error」,係打錯字:Internal Server Error 係 500(505 係 HTTP Version Not Supported)。考試應該要 500,但最好問下老師。
- 工具:
curl -v http://hkmu.edu.hk(預設就係-X GET)會顯示 header。(NE) Postman、browser devtools。
GET vs POST
| GET | POST | |
|---|---|---|
| 用途 | 向某個資源攞數據 | 送數據去開新或者更新資源 |
| 數據擺邊 | URL 嘅 query string ?fname=Yishu&lname=Li | Request body name1=value1&name2=value2 |
| 會唔會 cache | 會 | 永遠唔會 |
| Browser history/bookmark | 有/得 | 冇/唔得 |
| 長度限制 | 有 | 冇 |
| 敏感資料 | 千祈唔好(URL 睇得到) | 可以 |
內置 module(唔使 install)
http開 server,處理 req/res:http.createServer((req, res) => {...}).listen(8099)。url拆網址:url.parse(req.url, true),true會將 query string 變做 object(.query)。仲有.pathname、.host、.port、.search、.hash等等。querystring拆同砌 query string(處理 POST body 會用到)。fs處理檔案(fs.readFile、fs.exists)。
// 攞 Node 送嘅兩件工具:http 開舖,url 睇地址
const http = require('http'), url = require('url')
// 開舖!每有客人敲門就行呢度
http.createServer((req, res) => {
// 睇清楚客人想去邊、帶咗咩嘢嚟
const parsedURL = url.parse(req.url, true)
// 客人去 /login 就招呼佢
if (parsedURL.pathname == '/login') {
// 200 = 冇問題,俾佢一頁網頁
res.writeHead(200, { 'Content-Type': 'text/html' })
// 話返俾佢聽:你幾點嚟、打咗咩名同密碼
res.end(`<p>${req.method} request received at ${new Date()}</p>
<p>You entered <b>${parsedURL.query.name}</b> and <b>${parsedURL.query.password}</b></p>`)
} else {
// 其他地方:404 = 冇呢間房
res.writeHead(404, { 'Content-Type': 'text/plain' })
// 同佢講「搵唔到」
res.end('404 Not Found\n')
}
// 喺 8099 號門口等客
}).listen(8099)
- 一定要設
Content-Type,client 先知點處理個 body:text/html、text/plain、image/jpeg、application/json。 - POST:數據喺 request body 入面,通常嚟自一個 HTML
<form method="post">,而呢個 HTML 係 server 自己由 project folder 送出去。收齊個 body,再用querystring拆。 - Query parameter:
/greetings/sayHello?name=raymond就攞到queryAsObject.name。冇嘅話就用返「Hello there!」。
每個 server app 都做四樣嘢
- 喺一個 TCP port 度聽,等 request。
- 認出係咩 request(path 同 method),拆 parameter,唔識嘅一律回 404。
- 處理個 request。
- 用純文字、HTML 或者 JSON 回覆。
開發步驟:開 app folder,寫 app.js(需要嘅話加 HTML)同 package.json,行 npm install 同 npm start,再用 browser、curl 或者 HTML form 測試。
6. 唔考嘅嘢(一句帶過)
- Appendix I,deploy 上 cloud:push 上 GitHub,再 deploy 去 Render(要信用卡)或者 Azure Web App(學生戶口)。完咗科記得暫停或者刪咗佢,費事俾錢。
- Appendix II,JS 基礎:data type(
null= 刻意話冇值,undefined= 未設定,NaN)、字串、regex、object/JSON、array(splice收一個 index 同數量)、function。雖然唔考,但 Node 題目都會出呢啲語法。 - Appendix III,error handling:operational error(runtime)vs functional error(bug);
throw、try/catch/finally、call stack、Promise 用.then().catch()。
7. 可能會考嘅題目(嚟自 question set)
insertOne冇俾_id會點?MongoDB 會自動加一個ObjectId做_id。- 淨係要
name、唔要_id?find({}, { name: 1, _id: 0 })。 updateMany({}, ...)個{}係咩意思?即係全部 document。deleteOne({})vsdeleteMany({}):一個刪第一份,一個刪晒全部。$push、$pull、$pop、$set有咩分別。- 某條 pipeline 入面
$group做緊咩?$unwind會出咩? - References vs embedded(normalised vs denormalised),幾時應該 embed(一次 query 攞晒)。
- Node.js 解決咗咩問題?(non-blocking I/O、一個 thread 處理大量同時 request、慳記憶體)
- Event loop 嘅角色 · sync vs async I/O · callback 規矩(error 擺第一)·
JSON.parsevsJSON.stringify。 package.json、npm install、npm start各自做咩。- 點解要 API key?(向外部服務證明身份,例如 OpenWeather)點解 whitelist
0.0.0.0/0? localhost+ port 嘅意思 · GET vs POST · status code 分類 ·Content-Type有咩用。- 點解用 Ubuntu/VM 做開發?
缺咗嘅嘢:有啲 slide 淨係 screenshot,抽唔到文字,包括 Lecture 2 demo screenshot、Lecture 3 嘅 update operator 表同 aggregation 每個 stage 嘅輸出,同 Lecture 5 嘅
httpTemplate1/2 同 POST 例子。上面啲 code 係跟前後文同 lab 砌返出嚟,想知老師用嘅確實 template,要返去睇 PDF。