wordpress_blog

This is a dynamic to static website.

Complete MongoDB Tutorial

#1 – What is MongoDB?

In this series you’ll learn how to use MongoDB (a NoSQL database) from scratch. You’ll also learn how to integrate it into a simple Node.js API.

#2 – Installing MongoDB

Learn how to install MongoDB locally onto your computer.

#3 – Collections & Documents

#4 – Using MongoDB Compass

#5 – Using the MongoDB Shell

指令

  • show dbs
  • use database’s

使用其他終端機 – 指令

  • mongosh
  • cls
  • db
  • show collections
  • help
  • exit

#6 – Adding New Documents

指令

// insertOne
db.books.insertOne({title: "The Color of Magic", author: "Terry Pratchett", pages: 300, rating: 7, genres: ["fantasy", "magic"]})
// insertMany
db.books.insertMany([{title: "The Light Fantastic", author: "Terry Pratchett", pages: 250, rating: 6, genres: ["fantasy"]}, {title: "Dune", author: "Frank Herbert", pages: 500, rating: 10, genres: ["sci-fi", "dystopian"]}])

#7 – Finding Documents

指令

  • db.books.find()
  • db.books.find({author: “Terry Pratchett”})
  • db.books.find({author: “Terry Pratchett”, rating: 7})
  • db.books.find({author: “Brandon Sanderson”})
  • db.books.find({author: “Brandon Sanderson”}, {title: 1, author: 1})
  • db.books.find({}, {title: 1, author: 1})
  • db.books.find({_id: ObjectId(“650be28b103e76e586910c81”)})

#8 – Sorting & Limiting Data

指令

  • db.books.find().count()
  • db.books.find({ author: “Brandon Sanderson” }).count()
  • db.books.find().limit(3)
  • db.books.find().limit(3).count()
  • db.books.find().sort({ title: 1 })
  • db.books.find().sort({ title: -1 })
  • db.books.find().sort({ title: 1 }).limit(3)

#9 – Nested Documents

指令

// insertOne
db.books.insertOne({title: "The Way of Kings", author: "Brandon Sanderson", rating: 9, pages: 400, genres: ["fantasy"], reviews: [{name: "Yoshi", body: "Great book!!"}, {name: "mario", body: "so so"}]})
// insertMany
db.books.insertMany([{title: "The Light Fantastic", author: "Terry Pratchett", pages: 250, rating: 6, genres: ["fantasy", "magic"], reviews: [{name:"luigi", body: "it was pretty good"}, {name: "bowser", body: "loved it!!"}]}, {title: "The Name of the Wind", "author": "Patrick Rothfuss", page: 500, "rating": 10, genres: ["fantasy"], review: [{name: "peach", body: "one of my favs"}]}, {title: "The Color of Magic", "author": "Terry Pratchett", page: 350, "rating": 8, genres: ["fantasy", "magic"], review: [{name: "luigi", body: "it was ok"}, {name: "bowser", body: "really good book"}]}, {title: "1984", "author": "George Orwell", page: 300, "rating": 6, genres: ["sci-fi", "dystopian"], review: [{name: "peach", body: "not my cup of tea"}, {name: "mario", body: "meh"}]}])

#10 – Operators & Complex Queries

指令

  • db.books.find({rating: 7})
  • db.books.find({ rating: {$gt: 7}})
  • db.books.find({ rating: {$gt: 8}})
  • db.books.find({ rating: {$lte: 8}})
  • db.books.find({ rating: {$gte: 8}})
  • db.books.find({ rating: {$gt: 7}, author: “Patrick Rothfuss”})
  • db.books.find({$or: [{rating: 7}, {rating: 9}]})
  • db.books.find({$or: [{rating: 7}, {author: “Terry Pratchett”}]})
  • db.books.find({$or: [{pages: {$lt: 300}}, {pages: {$gt: 400}}]})

#11 – Using $in & $nin

指令

  • db.books.find({ rating: {$in: [7,8,9]}})
  • db.books.find({$or: [{rating: 7}, {rating: 8}, {rating: 9}]})
  • db.books.find({rating: {$nin: [7,8,9]}})
  • db.books.find({rating: {$nin: [7,8]}})

#12 – Querying Arrays

指令

  • db.books.find({genres: “fantasy”})
  • db.books.find({genres: “magic”})
  • db.books.find({genres: [“magic”]})
  • db.books.find({genres: [“fantasy”]})
  • db.books.find({genres: [“fantasy”, “magic”]})
  • db.books.find({genres: {$all: [“fantasy”, “sci-fi”]}})
  • db.books.find({“reviews.name”: “luigi”})

#13 – Deleting Documents

事先使用 MongoDB Compass EXPORT DATA 把資料匯出成JSON檔案。

指令

  • db.books.find()
  • db.books.deleteOne({_id: ObjectId(“650d22be248ed3d1c20642d0”)})
  • db.books.deleteMany({author: “Terry Pratchett”})

使用 MongoDB Compass ADD DATA 把檔案匯入。

#14 – Updating Documents

指令

  • db.books.updateOne({_id: ObjectId(“650d22be248ed3d1c20642cf”)}, {$set: {rating: 8, pages: 360}})
  • db.books.updateMany({author: “Terry Pratchett”}, {$set: {author: “Terry Pratchet”}})
  • db.books.updateOne({_id: ObjectId(“650d22be248ed3d1c20642d0”)}, {$inc: {pages: 2}})
  • db.books.updateOne({_id: ObjectId(“650d22be248ed3d1c20642d0”)}, {$inc: {pages: -2}})
  • db.books.updateOne({_id: ObjectId(“650d22be248ed3d1c20642d0”)}, {$pull: {genres: “fantasy”}})
  • db.books.updateOne({_id: ObjectId(“650d22be248ed3d1c20642d0”)}, {$push: {genres: “fantasy”}})
  • db.books.updateOne({_id: ObjectId(“650d22be248ed3d1c20642d0”)}, {$push: {genres: {$each: [“1″,”2”]}}})

#15 – MongoDB Drivers

指令 & 操作步驟

  1. npm init
  2. 建立一個 app.js 檔案
  3. npm install express –save
  4. npm install -g nodemon
  5. nodemon app
  6. http://localhost:3000/books
  7. 新增終端 npm install mongodb –save
// app.js
const express = require('express')

// init app & middleware
const app = express()

app.listen(3000, () => {
  console.log('app listening on port 3000')
})

// routes
app.get('/books', (req, res) => {
  res.json({mssg: "welcome to the api"})
})

#16 – Connecting to MongoDB

操作步驟

  1. 建立一個 db.js 檔案
  2. 修改 app.js 檔案內容
// db.js
const { MongoClient } = require('mongodb')

let dbConnection

module.exports = {
  connectToDb: (cb) => {
    MongoClient.connect('mongodb://localhost:27017/bookstore')
      .then((client) => {
        dbConnection = client.db()
        return cb()
      })
      .catch(err => {
        console.log(err)
        return cb(err)
      })
  },
  getDb: () => dbConnection
}
// app.js
const express = require('express')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  res.json({mssg: "welcome to the api"})
})

#17 – Cursors & Fetching Data

操作步驟

  1. 繼續修改 app.js 檔案內容
// app.js
const express = require('express')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

#18 – Finding Single Documents

操作步驟

  1. 繼續修改 app.js
  2. 使用 URL 測試是否能正常找到單一文件 http://localhost:3000/books/650d22be248ed3d1c20642cf
  3. 增加一些 ObjectId 布林判斷 app.js
// app.js - 1
const express = require('express')
const { ObjectId } = require('mongodb')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

app.get('/books/:id', (req, res) => {

  db.collection('books')
    .findOne({_id: new ObjectId(req.params.id)})
    .then(doc => {
      res.status(200).json(doc)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not fetch the document'})
    })

})
// app.js -3
const express = require('express')
const { ObjectId } = require('mongodb')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

app.get('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .findOne({_id: new ObjectId(req.params.id)})
    .then(doc => {
      res.status(200).json(doc)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not fetch the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
  
})

#19 – Using POSTMAN

Request

  • http://localhost:3000/books
  • http://localhost:3000/books/650d1421248ed3d1c20642cc

#20 – Handling POST Request

操作步驟

  1. 在 app.js 新增 post 相關程式碼
  2. 使用 POSTMAN 請求 POST 方法
  3. http://localhost:3000/books
  4. Body > raw 貼上準備好的資料內容然後送出
  5. 可以看到 Response Body 呈現的訊息
  6. 點擊之前的 Get Collection – books 測試
// app.js
const express = require('express')
const { ObjectId } = require('mongodb')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()
app.use(express.json())

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

app.get('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .findOne({_id: new ObjectId(req.params.id)})
    .then(doc => {
      res.status(200).json(doc)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not fetch the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
  
})

app.post('/books', (req, res) => {
  const book = req.body

  db.collection('books')
    .insertOne(book)
    .then(result => {
      res.status(201).json(result)
    })
    .catch(err => {
      res.status(500).json({err: 'Could not create a new document'})
    })
})
// Body > raw JSON
{
  "title": "The Final Empire",
  "author": "Brandon Sanderson",
  "rating": 9,
  "pages": 420,
  "genres": [
    "fantasy",
    "magic"
  ],
  "reviews": [
    {
      "name": "Shaun",
      "body": "Couldn't put this book down."
    },
    {
      "name": "Chun-Li",
      "body": "Love it."
    }
  ]
}

#21 – Handling DELETE Requests

操作步驟

  1. 在 app.js 新增 delete 相關程式碼
  2. 使用 POSTMAN 請求 DELETE 方法
  3. http://localhost:3000/books/650d22be248ed3d1c20642d0
  4. 送出後可以看到 Response Body 的訊息
  5. 點擊 Get 方法查看是否有刪除資料
// app.js
const express = require('express')
const { ObjectId } = require('mongodb')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()
app.use(express.json())

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

app.get('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .findOne({_id: new ObjectId(req.params.id)})
    .then(doc => {
      res.status(200).json(doc)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not fetch the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
  
})

app.post('/books', (req, res) => {
  const book = req.body

  db.collection('books')
    .insertOne(book)
    .then(result => {
      res.status(201).json(result)
    })
    .catch(err => {
      res.status(500).json({err: 'Could not create a new document'})
    })
})

app.delete('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .deleteOne({_id: new ObjectId(req.params.id)})
    .then(result => {
      res.status(200).json(result)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not delete the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
})

#22 – PATCH Requests

操作步驟

  1. 在 app.js 新增 PATCH 相關程式碼
  2. 使用 POSTMAN 請求 PATCH 方法
  3. 因為出現錯誤,有重新 import bookstore.books 檔案
  4. http://localhost:3000/books/650d1421248ed3d1c20642cc
  5. Body > raw JSON 更新資料後送出會呈現 Body 訊息
  6. 使用 GET Collection 查看是否有正確更新
// app.js
const express = require('express')
const { ObjectId } = require('mongodb')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()
app.use(express.json())

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

app.get('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .findOne({_id: new ObjectId(req.params.id)})
    .then(doc => {
      res.status(200).json(doc)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not fetch the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
  
})

app.post('/books', (req, res) => {
  const book = req.body

  db.collection('books')
    .insertOne(book)
    .then(result => {
      res.status(201).json(result)
    })
    .catch(err => {
      res.status(500).json({err: 'Could not create a new document'})
    })
})

app.delete('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .deleteOne({_id: new ObjectId(req.params.id)})
    .then(result => {
      res.status(200).json(result)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not delete the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
})

app.patch('/books/:id', (req, res) => {
  const updates = req.body

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .updateOne({_id: new ObjectId(req.params.id)}, {$set: updates})
    .then(result => {
      res.status(200).json(result)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not update the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
})
Body > raw JSON
{
  "pages": 350,
  "rating": 8
}

#23 – Pagination

In this MongoDB tutorial I’ll explain how to implement pagination into your requests.

操作步驟

  1. 在 app.js 新增關於 pagination 程式碼
  2. 使用 POSTMAN 請求 GET 方法
    以下兩種結果會相同
  3. http://localhost:3000/books
  4. http://localhost:3000/books?p=0
  5. 使用 http://localhost:3000/books?p=1
    會忽略前面的資料
  6. http://localhost:3000/books?p=2
    因為沒有資料會出現空陣列
// app.js
const express = require('express')
const { ObjectId } = require('mongodb')
const { connectToDb, getDb } = require('./db')

// init app & middleware
const app = express()
app.use(express.json())

// db connection
let db

connectToDb((err) => {
  if (!err) {
    app.listen(3000, () => {
      console.log('app listening on port 3000')
    })
    db = getDb()
  }
})

// routes
app.get('/books', (req, res) => {
  // current page
  const page = req.query.p || 0
  const booksPerPage = 3

  let books = []

  db.collection('books')
    .find()
    .sort({ author: 1 })
    .skip(page * booksPerPage)
    .limit(booksPerPage)
    .forEach(book => books.push(book))
    .then(() => {
      res.status(200).json(books)
    })
    .catch(() => {
      res.status(500).json({error: 'Could not fetch the documents'})
    })
})

app.get('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .findOne({_id: new ObjectId(req.params.id)})
    .then(doc => {
      res.status(200).json(doc)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not fetch the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
  
})

app.post('/books', (req, res) => {
  const book = req.body

  db.collection('books')
    .insertOne(book)
    .then(result => {
      res.status(201).json(result)
    })
    .catch(err => {
      res.status(500).json({err: 'Could not create a new document'})
    })
})

app.delete('/books/:id', (req, res) => {

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .deleteOne({_id: new ObjectId(req.params.id)})
    .then(result => {
      res.status(200).json(result)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not delete the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
})

app.patch('/books/:id', (req, res) => {
  const updates = req.body

  if (ObjectId.isValid(req.params.id)) {
    db.collection('books')
    .updateOne({_id: new ObjectId(req.params.id)}, {$set: updates})
    .then(result => {
      res.status(200).json(result)
    })
    .catch(err => {
      res.status(500).json({error: 'Could not update the document'})
    })
  } else {
    res.status(500).json({error: 'Not a valid doc id'})
  }
})

#24 – Indexes

In this mongodb tutorial we’ll talk about indexes and see how to create them.

簡報

  • db.collection(“books”).find({“rating”: 10})

指令 & 操作步驟

  1. 使用終端機執行 mongosh
  2. 使用 bookstore 資料庫 use bookstore
  3. db.books.find({rating: 8}).explain(‘executionStats’)
  4. db.books.createIndex({ rating: 8 })
  5. db.books.getIndexes()
  6. db.books.dropIndex({rating: 8})
  7. db.books.getIndexes()

#25 – MongoDB Atlas

In this mongodb tutorial you’ll learn how to use MongoDB Atlas, a Cloud Database service which allows you to easily set up a hosted database online.

操作步驟

  1. 註冊或登入 MongoDB
  2. DEPLOYMENT > Database 選擇建立一個 Database
  3. 選擇 Shared 免費方案
  4. aws > default 或者自行選擇 > Cluster Name 默認原本名稱 > 建立 Cluster
  5. Security Quickstart 可以設定 Username 和 Password
  6. 設定好後可以到 Database Access 查看
  7. Network Access > 新增一個 IP address > 在這裡選擇 ALLOW ACCESS FROM ANYWHERE 僅作測試使用,之後生產版本請勿選擇這個選項
  8. 到 Database Deployment 點擊 Connection > 選擇 Connect your application
  9. Add your connection string into your application code
  10. 在 db.js 修改成指定的 connection string > 修改設定的 Username 和 Password
  11. 我們不需要修改這些 Request,我們仍然使用這些 Request 關於 localhost
  12. Mongodb online 資料庫尚未有任何資料 > 可以 post 新的資料到線上資料庫 > Browse Collections
// db.js
const { MongoClient } = require('mongodb')

let dbConnection
let uri = '指定的 connection string'

module.exports = {
  connectToDb: (cb) => {
    MongoClient.connect(uri)
      .then((client) => {
        dbConnection = client.db()
        return cb()
      })
      .catch(err => {
        console.log(err)
        return cb(err)
      })
  },
  getDb: () => dbConnection
}