برنامه‌نویسی

آموزش توسعه‌ی یک برنامه‌ی ساده با Node.js و MongoDB


۸ اردیبهشت ۱۴۰۰
آموزش توسعه‌ی یک برنامه‌ی ساده با node.js و mongoDB

هدف این مقاله باتوجه به عنوان آن کاملا مشخص است اما برای توضیحات بیشتر باید بگوییم که می‌خواهیم یک برنامه‌ی ساده‌ی Todo را با Node.js توسعه دهیم و برای این کار از Mongoose که یک کتابخانه‌ی بسیار محبوب برای اتصال برنامه‌های Node.js به MongoDB است، استفاده خواهیم کرد.

Mongoose چیست؟

Mongoose را می‌توان یک کتابخانه‌ی ODM (Object Data Modeling) برای اتصال برنامه‌های Node.js به دیتابیس MongoDB دانست که با استفاده از آن می‌توانید روابط بین داده‌ها و اعتبارسنجی Schema را مدیریت کنید.

mongoose چیست؟

تفاوت MongoDB و دیتابیس‌های مبتنی‌ بر SQL

MongoDB یک دیتابیس NoSQL است که با مطالعه‌ی مقاله‌ی مقایسه SQL و NoSQL، کدام را انتخاب کنیم؟ می‌توانید اطلاعات بیشتری از تفاوت‌های این دو نوع دیتابیس کسب کنید اما به‌طور کلی، دیتابیس‌های NoSQL بدون Schema یا به‌عبارتی Schema-less هستند. این یعنی شما می‌توانید داده‌های json خود را بدون پیروی از ساختار خاصی در آن ذخیره کنید. افزایش سرعت توسعه‌ی برنامه از دیگر مزایای دیتابیس‌های NoSQL است زیرا پیچیدگی‌های کاری ما را کم‌تر می‌کند.

برای درک بهتر این موضوع‌ها می‌توانید تصویر زیر را مشاهده کنید که یک مثال ساده برای مقایسه‌ی نحوه‌ی ذخیره‌سازی داده‌ها در MongoDB و SQL است.

نحوه‌ی ذخیره سازی داده‌ها در دیتابیس mongodb
نحوه‌ی ذخیره سازی داده‌ها در mysql

بررسی اصطلاح‌های موجود در دیتابیس‌های NoSQL

Collections

Collections در دیتابیس‌های NoSQL معادلی برای Tables در دیتابیس‌های SQL است و ما می‌توانیم داده‌های json خود را در آن ذخیره کنیم.

Documents

Documents معادلی برای Records یا Rows در دیتابیس‌های SQL است با این تفاوت که یک SQL Row می‌تواند به داده‌ی دیگری در Tables ارجاع داده شود.

Fields

Fields یا attributes معادلی برای Columns در Table دیتابیس‌های SQL است.

Schema

اگرفراموش نکرده باشید در بخش قبل گفتیم که دیتابیس‌های NoSQL مانند MongoDB از Schema خاصی پیروی نمی‌کنند. بااین‌حال ما می‌توانیم از Mongoose Schema در برنامه‌ی خود استفاده کرده و ساختار Documentها را در آن مشخص کنیم.

Models

Models با دریافت Schema یک instance از Document را معادل با دیتابیس‌های رابطه‌ای برای ما ایجاد می‌کند.

Mongoose در عمل

ممکن است با توضیح‌های بالا در رابطه با Models و Schema سوال‌هایی در ذهن شما به‌وجود آمده باشد که سعی می‌کنیم در ادامه‌ی مقاله با توضیح‌های بیشتر به آن‌ها پاسخ دهیم.

مقایسه‌ی Schema و Model در Mongoose

Mongoose Model را می‌توان یک Wrapper برای Mongoose Schema دانست. در Mongoose Schema می‌توانیم ساختار Document، مقادیر پیش‌فرض، اعتبارسنجی‌های مورد نیاز و … را تعریف کنیم درحالی‌که Mongoose Model یک interface از دیتابیس در اختیار ما قرار می‌دهد که به‌کمک آن می‌توانیم عملیات CRUD را بر روی دیتابیس اجرا کنیم.

در ادامه‌ی این بخش بعضی از کدهای مربوطه را قرار می‌دهیم اما سریعا وارد عمل نشوید و فقط توضیح‌ها را دنبال کنید.

قبل از ایجاد یک Model باید سه فرایند کلی طی شود:

  1. فراخوانی Mongoose
  2. تعریف Schema
  3. Export کردن Model

فراخوانی Mongoose

موردی که باید به آن توجه داشته باشید این است که تعریف Schema و Model نیازی به اتصال دیتابیس ندارد و در ادامه‌ی مقاله به این موضوع خواهیم پرداخت بنابراین برای فراخوانی Mongoose از کدهای زیر استفاده خواهیم کرد:

const mongoose = require('mongoose')
const Schema = mongoose.Schema;

تعریف Schema

در این بخش سعی داریم یک Schema با نام todoSchema ایجاد کنیم. برای ایجاد این Schema باید یک Object را به‌عنوان پارامتر بهnew Schema() پاس دهیم. درون این Object از یک key با نام description استفاده کرده‌ایم و به‌عنوان مقدار آن از یک Object دیگر استفاده کرده‌ایم که type و required بودن آن را مشخص کرده است:

const todoSchema = new Schema(
  {
    description: {
      type: String,
      required: true,
    },
    completed: {
      type: Boolean,
      default: false,
    },
  },
  {
    timestamps: true,
  }
);

به‌همین ترتیب فیلد دیگری با نام completed وجود دارد که type آن را Boolean قرار داده‌ایم و به‌طور پیش‌فرض مقدار آن false است.

اگر با دقت به کد فوق نگاه کنید متوجه خواهید شد که در پارامتر دوم یک key با نام timestamps با مقدار true وجود دارد. این پارامتر documentهایی با نام createdAt و updatedAt را به دیتابیس ما اضافه می‌کند.

علاوه‌براین‌ها در رابطه با typeهای مجاز نیز می‌توانید از لیست زیر استفاده کنید:

  • Array
  • Boolean
  • Buffer
  • Date
  • Mixed
  • Number
  • ObjectId
  • String

Export کردن Model

با استفاده از Schema‌ای که در مرحله‌ی قبل تعریف کردیم می‌توانیم Model خود را ایجاد کرده و آن را Export کنیم. برای این کار از model constructor در instance ایجاد شده از Mongoose کمک می‌گیریم و todoSchema را به آن پاس می‌دهیم:

var Todos = mongoose.model("Todo", todoSchema);

و پس از ایجاد Model باید در انتهای فایل آن را به‌شکل زیر Export کنیم:

module.exports = Todos;

توسعه‌ی برنامه

│   .env
│   .gitignore
│   .liaraignore
│   app.js
│   liara.json
│   package-lock.json
│   package.json
│
└───models
        todos.js

برای توسعه‌ی برنامه، یک پوشه با نام node-mongoose در مسیر دلخواه خود ایجاد کنید و بر اساس ساختار فوق باید مجددا درون آن یک پوشه‌ی جدید با نام models ایجاد کرده و فایل todos.js را در آن ایجاد کنید. درنهایت کدهای زیر را در فایل todos.js قرار دهید:

// models/todos.js

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const todoSchema = new Schema(
  {
    description: {
      type: String,
      required: [true, "please enter task details"],
    },
    completed: {
      type: Boolean,
      default: false,
    },
  },
  {
    timestamps: true,
  }
);

var Todos = mongoose.model("Todo", todoSchema);

module.exports = Todos;

ساختار پوشه‌‌های ما تا به اینجای کار به شکل زیر است:

node-mongoose
  - models
     - todos.js

حال با استفاده از Terminal سیستم‌عامل خود وارد پوشه‌ی node-mongoose شوید و مراحل زیر را به‌ترتیب انجام دهید:

  • یک فایل با نام app.js در ریشه‌ی پروژه ایجاد کنید.
  • دستور npm init -y را اجرا کنید.
  • برای نصب express، mongoose و dotenv دستورهای npm install express، npm install mongoose و npm install dotenv را اجرا کنید.
  • فایل .env را در مسیر اصلی پروژه ایجاد کنید تا در ادامه مقادیر DATABASE_URL و PORT را در آن مشخص کنیم.
  • همچنین فراموش نکنید که فایل .gitignore را در مسیر اصلی پروژه ایجاد کرده و فایل .env و پوشه‌ی node_modules را در آن قرار دهید تا از Push شدن داده‌های دسترسی به دیتابیس در GitHub یا GitLab جلوگیری شود اما برای اینکه ما به فایل .env برای استقرار برنامه در لیارا احتیاج داریم باید یک فایل دیگر با نام .liaraignore در مسیر اصلی پروژه ایجاد کرده و فقط پوشه‌ی node_modules را در آن قرار دهیم.

بیایید نگاهی به محتوای هر فایل داشته باشیم:

فایل .env

mongodb://<user>:<password>@<host>:<port>/<my-app>?authSource=admin
PORT=3000

فایل .gitignore

node_modules
.env

فایل .liaraignore

node_modules

فایل package.json

{
  "name": "node-mongoose",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "mongoose": "^5.12.3"
  }
}

فایل app.js

const express = require("express");
const mongoose = require("mongoose");
const dotenv = require("dotenv");

dotenv.config({ path: ".env" });
const PORT = process.env.PORT;
const dbURI = process.env.DATABASE_URL;

//model
const Tasks = require("./models/todos");

const connect = mongoose.connect(dbURI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
});

connect.then(
    (db) => {
        console.log("Connected Successfully to Mongodb Server");

    },
    (err) => {
        console.log(err);
    }
);

const app = express();

app.use(express.json());

app.listen(PORT, () => {
    console.log(`Server is running at Liara Nodejs Service`);
});

پیاده‌سازی عملیات CRUD با استفاده از Mongoose

Mongoose دارای یک API انعطاف‌پذیر است و روش‌های پیشنهادی زیادی برای انجام هر کاری ارائه می‌دهد. بااین‌حال برای ساده نگه داشتن مقاله به یک روش بسنده می‌کنیم اما این موضوع را به یاد داشته باشید که می‌توانید بیشتر کارهای مورد نظر خود را به بیش از یک روش انجام دهید.

ایجاد یک document جدید در دیتابیس برنامه

در اینجا باید یک Object با نام newTask ایجاد کنیم که پارامتر description در آن تعریف شده باشد زیرا یک فیلد اجباری است. پس از آن با استفاده از Mongoose model که متد create() را دراختیار ما قرار می‌دهد می‌توانیم داده‌های خود را به دیتابیس اضافه کرده و به‌دلیل promise بودن این متد می‌توانیم در صورت رخ دادن خطا، آن را دریافت کرده و نمایش دهیم:

let newTask = {
      description: "task added using create",
};

Tasks.create(newTask)
  .then((data) => {
      console.log(data);
   })
   .catch((err) => {
      console.log(err);
});

نمایش تمام documentهای موجود در دیتابیس

برای دریافت تمام documentهایی که در collection ما ذخیره شده‌اند می‌توانیم به‌شکل زیر عمل کنیم:

//all tasks

Tasks.find({})
   .then((data) => {
       console.log("All tasks", data);
    })
    .catch((err) => {
       console.log(err);
 });

نمایش یک document خاص از دیتابیس

برای گذاشتن شرط و نمایش یک document خاص می‌توانیم به‌شکل زیر عمل کنیم:

Tasks.find({ completed: false })
    .then((data) => {
        console.log("All tasks", data);
    })
    .catch((err) => {
        console.log(err);
    });

به‌روزرسانی یک document خاص از دیتابیس

در این بخش می‌خواهیم مقدار completed یک document با شناسه 606a05138d4e7f3f58bdd444 را از false به true تغییر دهیم:

Tasks.findByIdAndUpdate({ _id: "606a05138d4e7f3f58bdd444" }, {
    $set: { completed: true },
},
    { new: true, useFindAndModify: false } //get updated result
)
    .then((data) => {
        console.log("Updated todo data", data);
    })
    .catch((err) => {
        console.log(err);
    });

حذف یک یا تمام documentهای موجود در دیتابیس

برای حذف تمام documentهای موجود در دیتابیس می‌توانیم به‌صورت زیر عمل کنیم:

Tasks.remove({});

یا می‌توانیم فقط شناسه‌ی خاصی را به‌صورت زیر حذف کنیم:

Tasks.findByIdAndRemove('606a092b4036e4614c5ca3bb')
    .then((data) => {
        console.log("All tasks", data);
    })
    .catch((err) => {
        console.log(err);
    });

استقرار پروژه بر روی لیارا

ایجاد یک برنامه جدید

برای ایجاد یک برنامه‌ی جدید باید وارد حساب کاربریتان در لیارا شوید و در تب برنامه‌ها بر روی دکمه‌ی ایجاد برنامه کلیک کنید.

ایجاد یک برنامه‌ی جدید در لیارا

بلافاصله بعد از کلیک بر روی دکمه‌ی ایجاد برنامه یک صفحه‌ی جدید برای شما باز می‌شود که بایستی در آن پلتفرم مورد نظرتان را انتخاب کرده و یک شناسه‌ی یکتا برای برنامه‌ی جدید خود درنظر بگیرید.

انتخاب پلتفرم nodejs و ثبت شناسه برنامه

پس از مشخص کردن شناسه از شما خواسته می‌شود که پلن مورد نظرتان را به‌نسبت نیازهای زیرساخت برنامه انتخاب کنید و درنهایت پس از انتخاب پلن مورد نظر بر روی دکمه‌ی ایجاد برنامه کلیک کنید.

انتخاب پلن و ایجاد یک برنامه‌ی جدید

نصب Liara CLI

پس از ایجاد برنامه‌ی جدید به صفحه‌ی راهنما ریدایرکت می‌شوید که دستورالعمل‌های استقرار برنامه به‌صورت متنی به‌همراه آموزش ویدیویی در آن قرار داده شده است.

صفحه‌ی راهنمای پلتفرم nodejs در لیارا

همان‌طور که مشاهده می‌کنید برای شروع باید Liara CLI را نصب کنیم که این کار به‌کمک یک پکیج منیجر با نام npm انجام می‌شود بنابراین توصیه می‌شود که حتما آموزش نصب Nodejs روی ویندوز را مطالعه کنید زیرا نصب Nodejs از پیش‌نیازهای استفاده‌ی این پکیج منیجر است. پس از نصب Nodejs که به‌همراه آن npm هم نصب می‌شود می‌توانید با اجرای دستور npm -v از نصب موفقیت آمیز این پکیج منیجر اطمینان حاصل کرده و با خیال راحت دستور زیر را برای نصب Liara CLI اجرا کنید:

npm install -g @liara/cli

ورود به حساب کاربری با Liara CLI

پس از نصب Liara CLI به‌راحتی با اجرای دستور liara login و وارد کردن اطلاعات می‌توانید وارد حساب کاربریتان شوید اما نکته‌ای که باید به آن دقت داشته باشید، انتخاب موقعیت جغرافیایی صحیح است.

انتخاب بین موقعیت‌های ایران و آلمان برای ورود به حساب کاربری لیارا

درنهایت اگر پس از وارد کردن اطلاعات حساب کاربری، ورود شما با موفقیت انجام شود پیام You have logged in successfully. را در Terminal دریافت خواهید کرد.

ورود موفقیت‌آمیز به لیارا

ایجاد یک دیتابیس جدید

برای ایجاد یک دیتابیس جدید باید از پنل کاربری لیارا در تب دیتابیس‌ها بر روی دکمه‌ی راه‌اندازی دیتابیس کلیک کنید.

راه‌اندازی یک دیتابیس جدید در لیارا

در صفحه‌ای که بلافاصله پس از کلیک بر روی راه‌اندازی دیتابیس برای شما باز می‌شود باید نوع و نسخه‌ی دیتابیس را انتخاب کرده و یک شناسه‌ی یکتا برای دیتابیس خود درنظر بگیرید.

انتخاب دیتابیس mongodb و ثبت شناسه دیتابیس

همچنین می‌توانید در بخش شبکه، گزینه‌ی دسترسی از طریق شبکه‌ی عمومی را برای امنیت بیشتر خاموش کنید اما توجه داشته باشید که با قطع دسترسی عمومی فقط برنامه‌های لیارا می‌توانند با این دیتابیس ارتباط برقرار کنند.

قطع کردن دسترسی از طریق شبکه‌ی عمومی

درنهایت باید پلن مورد نظرتان را انتخاب کرده و بر روی گزینه‌ی راه‌اندازی و نصب دیتابیس کلیک کنید تا دیتابیس شما ایجاد شود.

انتخاب پلن و راه‌اندازی دیتابیس

پس از راه‌اندازی دیتابیس روی سرویس ایجاد شده کلیک کرده و از سایدبار سمت راست بر روی نحوه‌ی اتصال کلیک کنید.

نحوه‌ی اتصال به دیتابیس در لیارا

داده‌های مورد نیاز برنامه‌ی شما برای اتصال به دیتابیس MongoDB در این صفحه قرار دارد که باید این داده‌ها را در فایل .env وارد کنید:

DATABASE_URL=mongodb://root:<censored-password>@mongodb:27017/my-app?authSource=admin
PORT=3000

استقرار پروژه

برنامه‌ی ما پس از وارد کردن داده‌های مورد نیاز برای اتصال به دیتابیس در فایل .env آماده‌ی استقرار در لیارا است و با اجرای دستور liara deploy می‌توانیم پروژه‌ی فعلی را در لیارا مستقر کنیم اما برای ساماندهی عملیات استقرار و جلوگیری از خطاها می‌توانیم یک فایل با نام liara.json در مسیر اصلی پروژه ایجاد کرده و داده‌های مورد نیاز برای استقرار برنامه را به شکل زیر در آن وارد کنیم:

{
  "platform": "node",
  "app": "node-app",
  "port": 3000
}

با این روش دیگر نیازی به انتخاب نام و وارد کردن پورت برنامه نیست و با اجرای دستور liara deploy تمام فرایند استقرار برنامه به‌صورت خودکار انجام می‌شود.

منبع: https://blog.teachmebro.com/building-a-crud-application-using-node-js-and-mongodb-atlas