آموزش توسعهی یک برنامهی ساده با Node.js و MongoDB
۸ اردیبهشت ۱۴۰۰
هدف این مقاله باتوجه به عنوان آن کاملا مشخص است اما برای توضیحات بیشتر باید بگوییم که میخواهیم یک برنامهی سادهی Todo را با Node.js توسعه دهیم و برای این کار از Mongoose که یک کتابخانهی بسیار محبوب برای اتصال برنامههای Node.js به MongoDB است، استفاده خواهیم کرد.
Mongoose چیست؟
Mongoose را میتوان یک کتابخانهی ODM (Object Data Modeling) برای اتصال برنامههای Node.js به دیتابیس MongoDB دانست که با استفاده از آن میتوانید روابط بین دادهها و اعتبارسنجی Schema را مدیریت کنید.
تفاوت MongoDB و دیتابیسهای مبتنی بر SQL
MongoDB یک دیتابیس NoSQL است که با مطالعهی مقالهی مقایسه SQL و NoSQL، کدام را انتخاب کنیم؟ میتوانید اطلاعات بیشتری از تفاوتهای این دو نوع دیتابیس کسب کنید اما بهطور کلی، دیتابیسهای NoSQL بدون Schema یا بهعبارتی Schema-less هستند. این یعنی شما میتوانید دادههای json خود را بدون پیروی از ساختار خاصی در آن ذخیره کنید. افزایش سرعت توسعهی برنامه از دیگر مزایای دیتابیسهای NoSQL است زیرا پیچیدگیهای کاری ما را کمتر میکند.
برای درک بهتر این موضوعها میتوانید تصویر زیر را مشاهده کنید که یک مثال ساده برای مقایسهی نحوهی ذخیرهسازی دادهها در MongoDB و SQL است.
بررسی اصطلاحهای موجود در دیتابیسهای 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 باید سه فرایند کلی طی شود:
- فراخوانی Mongoose
- تعریف Schema
- 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);
});
استقرار پروژه بر روی لیارا
ایجاد یک برنامه جدید
برای ایجاد یک برنامهی جدید باید وارد حساب کاربریتان در لیارا شوید و در تب برنامهها بر روی دکمهی ایجاد برنامه کلیک کنید.
بلافاصله بعد از کلیک بر روی دکمهی ایجاد برنامه یک صفحهی جدید برای شما باز میشود که بایستی در آن پلتفرم مورد نظرتان را انتخاب کرده و یک شناسهی یکتا برای برنامهی جدید خود درنظر بگیرید.
پس از مشخص کردن شناسه از شما خواسته میشود که پلن مورد نظرتان را بهنسبت نیازهای زیرساخت برنامه انتخاب کنید و درنهایت پس از انتخاب پلن مورد نظر بر روی دکمهی ایجاد برنامه کلیک کنید.
نصب Liara CLI
پس از ایجاد برنامهی جدید به صفحهی راهنما ریدایرکت میشوید که دستورالعملهای استقرار برنامه بهصورت متنی بههمراه آموزش ویدیویی در آن قرار داده شده است.
همانطور که مشاهده میکنید برای شروع باید 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 در این صفحه قرار دارد که باید این دادهها را در فایل .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