§2024-06-09
-
not yet finished
-
Building a Node.js Blog Application with MongoDB and Design Patterns Anand Panchal Jun 6, 2023
機器: hc4nas02.yushei.net
¶Step 1. nodejs eviromental control, fnm
alexlai@hc4nas02:~$ which node npm npx
/run/user/1026/fnm_multishells/15667_1717891102554/bin/node
/run/user/1026/fnm_multishells/15667_1717891102554/bin/npm
/run/user/1026/fnm_multishells/15667_1717891102554/bin/npx
alexlai@hc4nas02:~$ fnm list
* v20.14.0 default, lts-latest
* system
¶Step2. create project directory
alexlai@hc4nas02:~$ cd
alexlai@hc4nas02:~$ mkdir -p nodejs_proj/yushei_blog && cd $_
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (yushei_blog)
version: (1.0.0)
description: A blog for YuShei using nodeJs, mongoDB
entry point: (index.js)
test command:
git repository:
keywords:
author: alexlai@h2jammy.yushei.net
license: (ISC)
About to write to /home/alexlai/nodejs_proj/yushei_blog/package.json:
{
"name": "yushei_blog",
"version": "1.0.0",
"description": "A blog for YuShei using nodeJs, mongoDB",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "alexlai@h2jammy.yushei.net",
"license": "ISC"
}
Is this OK? (yes)
¶Step3. install NodeJs modules
$ npm install express mongoose body-parser inversify reflect-metadata --save
$ ls
node_modules package.json package-lock.json
$ cat package.json
{
"name": "yushei_blog",
"version": "1.0.0",
"description": "A blog for YuShei using nodeJs, mongoDB",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "alexlai@h2jammy.yushei.net",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.2",
"express": "^4.19.2",
"inversify": "^6.0.2",
"mongoose": "^8.4.1",
"reflect-metadata": "^0.2.2"
}
}
starting from npm version 5 (released in 2017), the --save flag is no longer necessary because it is the default behavior.
¶Step 3: MVC, Model-View-Controller
The MVC design pattern separates the application into three main components: Model, View, and Controller. This separation helps to organize the codebase and improve maintainability. Let’s create the necessary files for each component:
- 3.01. Create a models directory and a Blog.js file inside it. This file will define the Mongoose schema for our blog posts.
const mongoose = require('mongoose');
const blogSchema = new mongoose.Schema({
title: { type: String, required: true },
content: { type: String, required: true },
});
module.exports = mongoose.model('Blog', blogSchema);
- 3.02. Create a views directory and a blogView.js file inside it. This file will handle rendering the blog posts to the user interface.
function renderBlog(blog) {
console.log(`Title: ${blog.title}`);
console.log(`Content: ${blog.content}`);
}
module.exports = renderBlog;
- 3.03. Create a controllers directory and a blogController.js file inside it. This file will handle the logic between the Model and the View.
const Blog = require('../models/Blog');
const renderBlog = require('../views/blogView');
async function createBlog(title, content) {
try {
const blog = new Blog({ title, content });
await blog.save();
renderBlog(blog);
} catch (error) {
console.error(error);
}
}
module.exports = createBlog;¥
¶Step 4: Configuring MongoDB Connection
Let’s configure the MongoDB connection in our project. Create a config directory and a database.js file inside it. Add the following code to establish the connection:
-
4.01. Create mongoDB a database ys_blog
- Naming Conventions:
- Databases: Use snake_case.
- Collections: Use UpperCamelCase.
- Fields: Use lowerCamelCase.
- Naming Conventions:
-
yushei.com.tw srv
alexlai@MacMini ~ % dig +short _mongodb._tcp.inLaneCatch.yushei.com.tw SRV
0 0 27017 hc4Jammy.yushei.com.tw.
0 0 27017 x8664Arch.yushei.com.tw.
0 0 27017 n2Boookworm.yushei.com.tw.
0 0 27017 n2Jammy.yushei.com.tw.
alexlai@MacMini ~ % dig +short _mongodb._tcp.ys20220318.yushei.com.tw SRV
0 0 27017 redisMongo03.yushei.com.tw.
0 0 27017 redisMongo05.yushei.com.tw.
0 0 27017 redisMongo04.yushei.com.tw.
- create user alexlai
use ys_blog
db.createUser(
{
user: "alexlai",
pwd: "alex1765", // or passwordPrompt(),
roles: [ { role: "readWrite", db: "ys_blog" },
{ role: "read", db: "reporting" } // if any
]
}
)
alexlai@n2Bookworm:~$ mongosh "mongodb+srv://siteRootAdmin:b23258585@inlaneCatch.yushei.com.tw/ys_blog?replicaSet=odroid01&authSource=admin&tls=false"
Current Mongosh Log ID: 6665318be4112959ba8db5fa
Connecting to: mongodb+srv://<credentials>@inlaneCatch.yushei.com.tw/ys_blog?replicaSet=odroid01&authSource=admin&tls=false&appName=mongosh+2.2.6
Using MongoDB: 7.0.0-rc8
Using Mongosh: 2.2.6
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
odroid01 [primary] ys_blog>
alexlai@n2Bookworm:~$ mongosh "mongodb+srv://siteRootAdmin:b23258585@inlaneCatch.yushei.com.tw/admin?replicaSet=odroid01&authSource=admin&tls=false"
Current Mongosh Log ID: 6665319df1b8918f178db5fa
Connecting to: mongodb+srv://<credentials>@inlaneCatch.yushei.com.tw/admin?replicaSet=odroid01&authSource=admin&tls=false&appName=mongosh+2.2.6
Using MongoDB: 7.0.0-rc8
Using Mongosh: 2.2.6
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
odroid01 [primary] admin> use ys_blog
switched to db ys_blog
odroid01 [primary] ys_blog> db.createUser(
... {
... user: "alexlai",
... pwd: "alex1765", // or passwordPrompt(),
... roles: [ { role: "readWrite", db: "ys_blog" }]
... }
... )
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1717902561, i: 1 }),
signature: {
hash: Binary(Buffer.from("d554451f8b1a7ea07bfb0d8df6e5083c4ebbd9ab", "hex"), 0),
keyId: Long("7326325939019710465")
}
},
operationTime: Timestamp({ t: 1717902561, i: 1 })
}
- test user alexlai
alexlai@n2Bookworm:~$ mongosh "mongodb+srv://alexlai:alex1765@inlaneCatch.yushei.com.tw/ys_blog?replicaSet=odroid01&authSource=ys_blog&tls=false"
Current Mongosh Log ID: 6665320e5a39d3fde88db5fa
Connecting to: mongodb+srv://<credentials>@inlaneCatch.yushei.com.tw/ys_blog?replicaSet=odroid01&authSource=ys_blog&tls=false&appName=mongosh+2.2.6
Using MongoDB: 7.0.0-rc8
Using Mongosh: 2.2.6
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
odroid01 [primary] ys_blog> db.runCommand({connectionStatus : 1})
{
authInfo: {
authenticatedUsers: [ { user: 'alexlai', db: 'ys_blog' } ],
authenticatedUserRoles: [ { role: 'readWrite', db: 'ys_blog' } ]
},
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1717908087, i: 1 }),
signature: {
hash: Binary.createFromBase64('+eEWpjkc8jW28VIZq5WukI3/FLQ=', 0),
keyId: Long('7326325939019710465')
}
},
operationTime: Timestamp({ t: 1717908087, i: 1 })
}
- 4.02. config/database.js
const mongoose = require('mongoose');
async function connectToDatabase() {
try {
await mongoose.connect('mongodb+srv://alexlai:alex1765@inlaneCatch.yushei.com.tw/ys_blog?replicaSet=odroid01&authSource=ys_blog&tls=false',
{
useNewUrlParser: true,
useUnifiedTopology: true,
}
);
console.log('Connected to MongoDB');
} catch (error) {
console.error('Failed to connect to MongoDB', error);
}
}
module.exports = connectToDatabase;
Step 5: Implementing Dependency Injection with InversifyJS
InversifyJS and InversifyJS enhances the modularity, maintainability, and testability of your Node.js applications by providing a robust framework for dependency injection. It is especially beneficial for large-scale applications where managing dependencies becomes complex and challenging.