Suprayogi, M.
Kom
NodeJS MongoDB
Alasan Pengunaan Backend
krn tdk aman jika code javascript frontend terkoneksi dg database
kode HTML,CSS,Javascript di browser dapat diekpose oleh pengunjung website.
Connection
The connection URI is the set of instructions that the driver uses to connect to a MongoDB deployment
Connection options:
maxPoolSize:Specifies the maximum number of clients or connections the driver can create in its
connection pool. This count includes connections in use,default 100.
w:Specifies the default write concern "w" field for the client, default null.
Atlas Connection Example
Menggunakan atlas
Contoh:
mongodb+srv://suprayogismg:<db_password>@clusteryogi.kntuf.mongodb.net/?retryWrites=true&w=
majority&appName=ClusterYogi
mongoshell
mongosh "mongodb+srv://clusteryogi.kntuf.mongodb.net/" --apiVersion 1 --username suprayogismg
persiapan
Install the Node.js Driver
npm i mongodb@3.6.11
koneksi ke database mongodb
db1.js
const { MongoClient, ServerApiVersion } = require("mongodb");
// Replace the placeholder with your Atlas connection string
const uri =
"mongodb+srv://<user>:<password>@hostname/?retryWrites=true&w=majority&appName=ClusterYogi";
//const uri = "mongodb://localhost:27017";
// Create a MongoClient with a MongoClientOptions object to set the Stable API version
const client = new MongoClient(uri, {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
}
}
);
async function run() {
try {
// Connect the client to the server (optional starting in v4.7)
await client.connect();
// Send a ping to confirm a successful connection
await client.db("admin").command({ ping: 1 });
console.log("Pinged your deployment. You successfully connected to MongoDB!");
} finally {
// Ensures that the client will close when you finish/error
await client.close();
}
}
run().catch(console.dir);
CRUD Operations:
CRUD (Create, Read, Update, Delete) operations allow you to work with the data stored in
MongoDB. The CRUD operation documentation is categorized in two sections:
• Read Operations find and return documents stored within your MongoDB database.
• Write Operations insert, modify, or delete documents in your MongoDB database.
Retrieve Data
You can perform a find operation to match documents on a set of criteria by calling the find() or
findOne() method
find1.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
// Get the database and collection on which to run the operation
const database = client.db("dbbuku");
const books = database.collection("buku");
// Query for a books that has the title ' Belajar Docker '
const query = { judul: "Belajar Docker" };
const options = {
// Sort matched documents in descending order by rating
sort: { "harga": -1 },
// Include only the `judul` and `harga` fields in the returned document
projection: { _id: 0, judul: 1, harga: 1 },
};
// Execute query
const book = await books.findOne(query, options);
// Print the document returned by findOne()
console.log(book);
} finally {
await client.close();
}
}
run().catch(console.dir);
find2.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const query = { harga: { $gte: 100000 } };
const options = {
sort: { judul: 1 },
projection: { _id: 0, judul: 1, harga: 1 },
};
const cursor = books.find(query, options);
if ((await books.countDocuments(query)) === 0) {
console.log("No documents found!");
}
for await (const doc of cursor) {
console.dir(doc);
}
} finally {
await client.close();
}
}
run().catch(console.dir);
Insert Documents
Insert1.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const doc = {
judul: "Pemrograman Backend",
pengarang: "Bambang Abdulah",
penerbit: "Andi-Offset",
harga: 120000
}
const result = await books.insertOne(doc);
console.log(`A document was inserted with the _id: ${result.insertedId}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Insert2.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const foods = database.collection("buku");
const docs = [
{judul: "Pemrograman C#",
pengarang: "Bambang Abdulah",
penerbit: "Andi-Offset",
harga: 80000 },
{judul: "Pemrograman Java",
pengarang: "Budi Purnama",
penerbit: "Andi-Offset",
harga: 90000 },
{judul: "Menggunakan Spring Boot",
pengarang: "Susi Similiky",
penerbit: "Andi-Offset",
harga: 120000 }
];
const options = { ordered: true };
const result = await foods.insertMany(docs, options);
console.log(`${result.insertedCount} documents were inserted`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Delete Documents
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const query = { judul: "Pemrograman Java" };
const result = await books.deleteOne(query);
if (result.deletedCount === 1) {
console.log("Successfully deleted one document.");
} else {
console.log("No documents matched the query. Deleted 0 documents.");
}
} finally {
await client.close();
}
}
run().catch(console.dir);
delete2.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const query = { judul: { $regex: "Belajar" } };
const result = await books.deleteMany(query);
console.log("Deleted " + result.deletedCount + " documents");
} finally {
await client.close();
}
}
run().catch(console.dir);
Update Documents
update1.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const filter = { judul: "Pemrograman Backend" };
const options = { upsert: true };
const updateDoc = {
$set: {
judul: `Pemrograman Backend dan mongoDB : ${Math.random()}`
},
};
const result = await books.updateOne(filter, updateDoc, options);
console.log(
`${result.matchedCount} document(s) matched the filter, updated
${result.modifiedCount} document(s)`,
);
} finally {
await client.close();
}
}
run().catch(console.dir);
update2.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const filter = { judul: "Pemrograman Backend" };
const options = { upsert: true };
const updateDoc = {
$set: {
judul: `Pemrograman Backend dan mongoDB : ${Math.random()}`
},
};
const result = await books.updateMany(filter, updateDoc, options);
console.log(
`${result.matchedCount} document(s) matched the filter, updated
${result.modifiedCount} document(s)`,
);
} finally {
await client.close();
}
}
run().catch(console.dir);
Replace Documents
replace.js
const { MongoClient, ServerApiVersion } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db("dbbuku");
const books = database.collection("buku");
const query = { judul: { $regex: "Backend" } };
const replacement = {
judul: 'Pemrograman Backend',
};
const result = await books.replaceOne(query, replacement);
console.log(`Modified ${result.modifiedCount} document(s)`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Membuat aplikasi Blog
operasi CRUD: Create Blog Post,Read Blog Post,Update Blog Post,Delete Blog Post
desain database/table,create database/table,connect to dbase & interact via NodeJS/express.
Konfigurai awal
Buat folder project ,inisialisasi project node , dan buka vscode
Konfigurai awal
Install module-module sbb:
npm install express
npm install express-ejs-layouts
npm install mongodb
Struktur Direktori Project
data/database.js
const mongodb=require('mongodb');
const MongoClient=mongodb.MongoClient;
let database;
async function connect(){
const client = await MongoClient.connect('mongodb://127.0.0.1:27017');
database = client.db('blog');
}
function getDb(){
if (!database){
throw{message:'database cnonection not establish'}
}
return database;
}
module.exports= {
connectToDb: connect,
getDb:getDb
}
Public/styles/base.css
/* Base styles & resets */
html {
font-family: 'Roboto Slab', serif;
color: rgb(46, 45, 48);
}
body {
margin: 0;
}
main {
width: 80%;
margin: 3rem auto;
}
a {
text-decoration: none;
color:rgb(89, 0, 255);
}
a:hover,
a:active {
color:rgb(232, 90, 245);
}
ul, ol {
list-style: none;
margin: 0;
padding: 0;
}
/* Global components */
.btn {
cursor: pointer;
font: inherit;
background-color: rgb(89, 0, 255);
border: 1px solid rgb(89, 0, 255);
color: white;
padding: 0.5rem 1.5rem;
border-radius: 4px;
}
.btn:hover,
.btn:active {
background-color: rgb(71, 4, 196);
border-color: rgb(71, 4, 196);
color: white;
}
.btn.btn-alt {
background-color: transparent;
border-color: transparent;
color:rgb(89, 0, 255);
}
.btn.btn-alt:hover,
.btn.btn-alt:active {
color:rgb(232, 90, 245);
}
/* Site-wide content / elements */
#main-header {
padding: 2rem 10%;
background-color: rgb(89, 0, 255);
display: flex;
justify-content: space-between;
align-items: center;
}
#logo a {
font-size: 2rem;
font-weight: bold;
color: white;
font-family: 'Roboto', sans-serif;
}
#main-header ul {
display: flex;
}
#main-header li {
margin-left: 2rem;
}
#main-header nav a {
color: white;
font-size: 1.25rem;
}
#main-header nav a:hover,
#main-header nav a:active {
color:rgb(255, 217, 0);
}
Public/styles/forms.css
form {
max-width: 25rem;
margin: 2rem auto;
}
h1 {
text-align: center;
}
label {
font-weight: bold;
display: block;
margin-bottom: 0.25rem;
}
input, textarea, select {
font: inherit;
padding: 0.5rem;
border-radius: 4px;
border: 1px solid rgb(204, 204, 204);
}
input:focus,
textarea:focus {
background-color: rgb(237, 228, 255);
}
input, textarea {
width: 100%;
}
.form-control {
margin: 0.5rem 0;
}
Public/styles/posts.css
/* All posts page */
#all-posts {
text-align: center;
}
#posts-list {
margin: 3rem auto;
max-width: 40rem;
}
.post-item {
margin: 1rem 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
border-radius: 8px;
padding: 1rem;
background-color: rgb(220, 204, 252);
}
.post-item h2,
.post-item p {
margin: 0.5rem 0;
}
.post-item-author {
font-style: italic;
}
.post-actions {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}
.post-actions .btn-alt {
padding: 0;
}
/* Post detail page */
#post-meta {
color: rgb(156, 149, 149);
}
#post-meta address {
display: inline;
}
#post-meta time {
font-style: italic;
}
#body {
white-space: pre-wrap; /* This ensures that line breaks and whitespace are kept
*/
}
routes/blog.js
const express = require('express');
const mongodb=require('mongodb');
const db = require('../data/database');
const ObjectId = mongodb.ObjectId;
const router = express.Router();
router.get('/', function(req, res) {
res.redirect('/posts');
});
router.get('/posts', async function(req, res) {
const posts=await db
.getDb()
.collection('posts')
.find({},{title:1,summary:1,'author.name':1})
.toArray();
res.render('posts-list',{posts:posts})
});
router.get('/new-post', async function(req, res) {
const authors= await db.getDb().collection('authors').find().toArray();
//console.log(authors);
res.render('create-post',{authors:authors});
});
router.get('/posts/:id',async function(req,res){
const postId=req.params.id;
const post= await db.getDb().collection('posts').findOne({_id:new
ObjectId(postId)},{summary:0});
if(!post){
return res.status(404).render('404');
}
post.humanReadableDate=post.date.toLocaleDateString('en-US',{
weekday:'long',
year:'numeric',
month:'long',
day:'numeric',
});
res.render('post-detail',{post:post});
});
router.get('/posts/:id/edit',async function(req,res){
const postId=req.params.id;
const post= await db
.getDb()
.collection('posts')
.findOne({_id:new ObjectId(postId)},{title:1,summary:1,body:1});
if(!post){
return res.status(404).render('404');
}
res.render('update-post',{post:post});
});
router.post('/posts', async function(req, res) {
//res.render('posts-list');
const authorId =new ObjectId(req.body.author);
const author=await db.getDb().collection('authors').findOne({_id:authorId});
const newPost={
title: req.body.title,
summary: req.body.summary,
body: req.body.content,
date: new Date(),
author: {
id: authorId,
name: author.name,
email: author.email
}
};
const result = await db.getDb().collection('posts').insertOne(newPost);
console.log(result);
res.redirect('/posts');
});
router.post('/posts/:id/edit',async function(req,res){
const postId=new ObjectId(req.params.id);
const result= await db
.getDb()
.collection('posts')
.updateOne(
{_id:postId},
{
$set:{
title: req.body.title,
summary:req.body.summary,
body:req.body.content
},
});
res.redirect('/posts');
});
router.post('/posts/:id/delete',async function(req,res){
const postId=new ObjectId(req.params.id);
const result = await db.getDb().collection('posts').deleteOne({_id:postId});
res.redirect('/posts');
});
module.exports = router;
views/includes/head.ejs
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
<%= title %>
</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Slab:wght@400
;700&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="/styles/base.css">
views/includes/header.ejs
<header id="main-header">
<div id="logo">
<a href="/">MyBlog</a>
</div>
<nav>
<ul>
<li>
<a href="/posts">All Posts</a>
</li>
<li>
<a href="/new-post">Create Post</a>
</li>
</ul>
</nav>
</header>
views/includes/post-item.ejs
<article class="post-item">
<h2><%= post.title %></h2>
<p class="post-item-author">By <%= post.author.name %></p>
<p><%= post.summary %></p>
<div class="post-actions">
<form action="/posts/<%= post._id %>/delete" method="POST">
<button class="btn btn-alt">Delete Post</button>
</form>
<a href="/posts/<%= post._id %>/edit">Edit Post</a>
<a class="btn" href="/posts/<%= post._id %>">View Post</a>
</div>
</article>
views/404.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('includes/head', { title: 'Not found!' }) %>
</head>
<body>
<%- include('includes/header') %>
<main>
<h1>We could not find this resource!</h1>
<p>Unfortunately, we were not able to find this resource.</p>
<a class="btn" href="/">Back To Safety!</a>
</main>
</body>
</html>
views/500.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('includes/head', { title: 'Something went wrong!' }) %>
</head>
<body>
<%- include('includes/header') %>
<main>
<h1>Oops, something went wrong!</h1>
<p>Unfortunately, something went wrong on our end - we're working on fixing
it!</p>
<a class="btn" href="/">Back To Safety!</a>
</main>
</body>
</html>
views/create-post.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('includes/head', { title: 'Add new post' }) %>
<link rel="stylesheet" href="/styles/forms.css">
</head>
<body>
<%- include('includes/header') %>
<main>
<h1>Add a new post</h1>
<form action="/posts" method="POST">
<div class="form-control">
<label for="title">Title</label>
<input type="text" id="title" name="title" required>
</div>
<div class="form-control">
<label for="summary">Summary</label>
<input type="text" id="summary" name="summary" required maxlength="255">
</div>
<div class="form-control">
<label for="content">Post Content</label>
<textarea id="content" name="content" required rows="5"></textarea>
</div>
<div class="form-control">
<label for="author">Select Author</label>
<select id="author" name="author">
<% for(const author of authors){%>
<option value="<%= author._id %>"><%= author.name %></option>
<%}%>
</select>
</div>
<button class="btn">Add Post</button>
</form>
</main>
</body>
</html>
views/post-detail.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('includes/head', { title: 'Post title' }) %>
<link rel="stylesheet" href="/styles/posts.css">
</head>
<body>
<%- include('includes/header') %>
<main id="post-detail">
<h1><%= post.title%></h1>
<section id="post-meta">
<address>
<a href="mailtto:<%= post.author.email %>"><%= post.author.name %></a>
</address>
<time datetime="<%= post.date %>"><%= post.humanReadableDate %>
</time>
</section>
<hr>
<section>
<p id="body"><%= post.body%></p>
</section>
</main>
</body>
</html>
views/ posts-lis.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('includes/head', { title: 'All Posts' }) %>
<link rel="stylesheet" href="/styles/posts.css">
</head>
<body>
<%- include('includes/header') %>
<main id="all-posts">
<h1>All Posts</h1>
<% if(!posts||posts.length==0) {%>
<p>No Posts found - maybe start creating some?</p>
<a class="btn" href="/new-post">Create a New Post</a>
<% }else{ %>
<ol id="posts-list"></ol>
<% for(const post of posts){ %>
<li>
<%- include('includes/post-item',{post:post}) %>
</li>
<% } %>
</ol>
<% } %>
</main>
</body>
</html>
views/update-post.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('includes/head', { title: 'Update post' }) %>
<link rel="stylesheet" href="/styles/forms.css">
</head>
<body>
<%- include('includes/header') %>
<main>
<h1>Update post</h1>
<form action="/posts/<%= post._id %>/edit" method="POST">
<div class="form-control">
<label for="title">Title</label>
<input type="text" id="title" name="title" value="<%= post.title%>"
required>
</div>
<div class="form-control">
<label for="summary">Summary</label>
<input type="text" id="summary" name="summary" value="<%= post.summary%>"
required maxlength="255">
</div>
<div class="form-control">
<label for="content">Post Content</label>
<textarea id="content" name="content" required rows="5"><%= post.body
%></textarea>
</div>
<button class="btn">Update Post</button>
</form>
</main>
</body>
</html>
App.js
const path = require('path');
const express = require('express');
const blogRoutes = require('./routes/blog');
const db = require('./data/database');
const app = express();
// Activate EJS view engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.urlencoded({ extended: true })); // Parse incoming request bodies
app.use(express.static('public')); // Serve static files (e.g. CSS files)
app.use(blogRoutes);
app.use(function (error, req, res, next) {
// Default error handling function
// Will become active whenever any route / middleware crashes
console.log(error);
res.status(500).render('500');
});
db.connectToDb().then(function(){
app.listen(3000);
});
Run program:
node App
buka browser ketik : http://localhost:3000