از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
Mongoose with Node.js – Object Data ModelingNoSQL انعطاف پذیری را به دنیای جدولی پایگاه های داده به ارمغان آورد. به ویژه MongoDB به یک گزینه عالی برای ذخیره اسناد JSON بدون ساختار تبدیل شد. داده ها به صورت JSON در رابط کاربری شروع می شوند و تغییرات بسیار کمی را برای ذخیره شدن تجربه می کنند، بنابراین از افزایش عملکرد و کاهش زمان پردازش سود می بریم. اما NoSQL …
سرفصلهای مطلب
معرفی
NoSQL انعطاف پذیری را به دنیای جدولی پایگاه داده ها آورد. به ویژه MongoDB به یک گزینه عالی برای ذخیره اسناد JSON بدون ساختار تبدیل شد. داده ها به صورت JSON در رابط کاربری شروع می شوند و تغییرات بسیار کمی را برای ذخیره شدن تجربه می کنند، بنابراین از افزایش عملکرد و کاهش زمان پردازش سود می بریم.
اما NoSQL به معنای فقدان کامل ساختار نیست. ما هنوز باید داده های خود را قبل از ذخیره سازی اعتبارسنجی و ارسال کنیم، و هنوز هم ممکن است نیاز به اعمال منطق تجاری برای آنها داشته باشیم. آن مکان است مانگوس پر می کند.
در این مقاله از طریق یک برنامه کاربردی مثالی یاد میگیریم که چگونه میتوانیم از Mongoose برای مدلسازی دادههای خود و اعتبارسنجی آنها قبل از ذخیره آن در MongoDB استفاده کنیم.
ما مدل یک برنامه Genealogy را خواهیم نوشت، شخصی با چند ویژگی شخصی، از جمله اینکه والدینش چه کسانی هستند. همچنین خواهیم دید که چگونه می توانیم از این مدل برای ایجاد و تغییر اشخاص و ذخیره آنها در MongoDB استفاده کنیم.
Mongoose چیست؟
MongoDB چگونه کار می کند
برای درک اینکه Mongoose چیست، ابتدا باید به طور کلی بفهمیم که MongoDB چگونه کار می کند. واحد اصلی داده ای که می توانیم در MongoDB ذخیره کنیم یک Document است. اگرچه به صورت باینری ذخیره میشود، اما وقتی یک پایگاه داده را پرس و جو میکنیم، نمایش آن را به عنوان یک شی JSON دریافت میکنیم.
اسناد مرتبط را می توان در مجموعه ها ذخیره کرد، مشابه جداول در پایگاه های داده رابطه ای. این همان جایی است که قیاس به پایان می رسد، زیرا ما تعریف می کنیم که چه چیزی را “اسناد مرتبط” در نظر بگیریم.
MongoDB ساختاری را اجرا نمی کند روی مدارک. برای مثال، میتوانیم این سند را در فایل ذخیره کنیم Person
مجموعه:
{
"name": "Alice"
}
و سپس در همان مجموعه، میتوانیم یک سند به ظاهر نامرتبط را بدون ویژگی یا ساختار مشترک ذخیره کنیم:
{
"latitude": 53.3498,
"longitude": 6.2603
}
در اینجا جدید بودن پایگاه های داده NoSQL نهفته است. ما برای دادههایمان معنا میسازیم و آنها را به روشی که بهترین میدانیم ذخیره میکنیم. پایگاه داده هیچ محدودیتی اعمال نخواهد کرد.
هدف مانگوس
اگرچه MongoDB ساختاری را تحمیل نمی کند، برنامه ها معمولاً داده ها را با یک ساختار مدیریت می کنند. ما دادهها را دریافت میکنیم و باید آنها را تأیید کنیم تا مطمئن شویم آنچه دریافت کردهایم همان چیزی است که نیاز داریم. ما نیز ممکن است نیاز داشته باشیم process داده ها به نوعی قبل از ذخیره آن. اینجا جایی است که Mongoose وارد می شود.
Mongoose یک بسته NPM برای برنامه های NodeJS است. این اجازه می دهد تا طرحواره هایی را برای داده های خود تعریف کنیم، در حالی که دسترسی به MongoDB را نیز انتزاعی می کند. به این ترتیب ما می توانیم اطمینان حاصل کنیم که تمام اسناد ذخیره شده دارای یک ساختار مشترک هستند و دارای ویژگی های مورد نیاز هستند.
حال بیایید ببینیم که چگونه a را تعریف کنیم طرحواره.
نصب Mongoose و ایجاد طرحواره شخص
بیایید یک پروژه Node را با ویژگی های پیش فرض و a راه اندازی کنیم طرح واره فرد:
$ npm init -y
با مقداردهی اولیه پروژه، بیایید پیش برویم و نصب کنیم mongoose
استفاده کردن npm
:
$ npm install --save mongoose
mongoose
به طور خودکار شامل خواهد شد mongodb
ماژول NPM نیز. خودتان مستقیماً از آن استفاده نخواهید کرد. آن را Mongoose اداره می کند.
برای کار با Mongoose، ما می خواهیم import آن را در اسکریپت های ما:
let mongoose = require('mongoose');
و سپس با استفاده از:
mongoose.connect('mongodb://localhost:27017/genealogy', {useNewUrlParser: true, useUnifiedTopology: true});
از آنجایی که پایگاه داده هنوز وجود ندارد، یکی ایجاد خواهد شد. ما از آخرین ابزار برای تجزیه رشته اتصال با تنظیم کردن استفاده می کنیم useNewUrlParser
به true
و همچنین از آخرین درایور MongoDB استفاده خواهیم کرد useUnifiedTopology
مانند true
.
mongoose.connect()
فرض می کند که سرور MongoDB به صورت محلی اجرا می شود روی پورت پیش فرض و بدون اعتبار. یکی از راههای ساده برای اجرای MongoDB، Docker است:
$ docker run -p 27017:27017 mongo
این container ایجاد شده برای ما کافی است تا Mongoose را امتحان کنیم، اگرچه داده های ذخیره شده در MongoDB پایدار نخواهد بود.
طرحواره و مدل شخص
پس از توضیحات لازم قبلی، اکنون می توانیم تمرکز کنیم روی نوشتن ما طرح واره فرد و تدوین الگویی از آن.
یک طرح در Mongoose به یک مجموعه MongoDB نقشه میدهد و قالب را برای همه اسناد تعریف میکند روی آن مجموعه تمام خصوصیات داخل طرحواره باید دارای یک تخصیص باشند SchemaType
. مثلا اسم ما Person
را می توان اینگونه تعریف کرد:
const PersonSchema = new mongoose.Schema({
name: { type: String},
});
یا حتی ساده تر، مانند این:
const PersonSchema = new mongoose.Schema({
name: String,
});
String
یکی از چندین است SchemaTypes
توسط Mongoose تعریف شده است. بقیه را می توانید در قسمت پیدا کنید مستندات مونگوس.
ارجاع به طرحواره های دیگر
ما میتوانیم انتظار داشته باشیم که همه برنامههای کاربردی با اندازه متوسط بیش از یک طرح داشته باشند و احتمالاً این طرحوارهها به نحوی به هم مرتبط شوند.
در مثال ما، برای نشان دادن یک درخت خانوادگی، باید دو ویژگی را به طرحواره خود اضافه کنیم:
const PersonSchema = new mongoose.Schema({
// ...
mother: { type: mongoose.Schema.Types.ObjectId, ref: 'Person' },
father: { type: mongoose.Schema.Types.ObjectId, ref: 'Person' },
});
یک فرد می تواند یک mother
و الف father
. راه نمایش این مورد در Mongoose با ذخیره شناسه سند ارجاع شده است. mongoose.Schema.Types.ObjectId
، نه خود شی.
این ref
ویژگی باید نام مدلی باشد که به آن ارجاع می دهیم. بعداً بیشتر در مورد مدلها خواهیم دید، اما در حال حاضر کافی است بدانید که یک طرحواره فقط به یک مدل مربوط میشود و 'Person'
مدل از است PersonSchema
.
مورد ما کمی خاص است زیرا هر دو mother
و father
همچنین شامل اشخاص خواهد بود، اما روش تعریف این روابط در همه موارد یکسان است.
اعتبار سنجی داخلی
همه SchemaType
s با اعتبار سنجی داخلی پیش فرض ارائه می شود. بسته به شرایط می توانیم محدودیت ها و سایر الزامات را تعریف کنیم روی انتخاب شده SchemaType
. برای دیدن چند نمونه، a اضافه می کنیم surname
، yearBorn
، و notes
به ما Person
:
const PersonSchema = new mongoose.Schema({
name: { type: String, index: true, required: true },
surname: { type: String, index: true },
yearBorn: { type: Number, min: -5000, max: (new Date).getFullYear() },
notes: { type: String, minlength: 5 },
});
همه ساخته شده است SchemaType
s می تواند باشد required
. در مورد ما می خواهیم همه افراد حداقل یک نام داشته باشند. این Number
نوع اجازه می دهد تا مقادیر حداقل و حداکثر را تنظیم کنید که حتی می توان آنها را محاسبه کرد.
این index
ویژگی Mongoose را وادار می کند که یک شاخص در پایگاه داده ایجاد کند. این امر اجرای کارآمد پرس و جوها را تسهیل می کند. در بالا، ما شخص را تعریف کردیم name
و surname
شاخص باشند. ما همیشه افراد را با نام آنها جستجو خواهیم کرد.
اعتبار سنجی سفارشی
ساخته شده در SchemaType
امکان سفارشی سازی را فراهم می کند. این به ویژه زمانی مفید است که ما یک ویژگی داریم که می تواند فقط مقادیر خاصی را نگه دارد. بیایید اضافه کنیم photosURLs
دارایی به ما Person
، آرایه ای از آدرس های اینترنتی عکس های آنها:
const PersonSchema = new mongoose.Schema({
// ...
photosURLs: (
{
type: String,
validate: {
validator: function(value) {
const urlPattern = /(http|https):\/\/(\w+:{0,1}\w*#)?(\S+)(:(0-9)+)?(\/|\/((\w#!:.?+=&%#!\-/)))?/;
const urlRegExp = new RegExp(urlPattern);
return value.match(urlRegExp);
},
message: props => `${props.value} is not a valid URL`
}
}
),
});
photosURLs
فقط آرایه ای از رشته ها است، photosURLs: (String)
. چیزی که این ویژگی را خاص می کند این است که برای تأیید اینکه مقادیر اضافه شده دارای فرمت URL اینترنتی هستند به اعتبارسنجی سفارشی نیاز داریم.
این validator()
تابع بالا از یک عبارت منظم استفاده می کند که با URL های معمولی اینترنتی مطابقت دارد که باید با آن شروع شود http(s)://
.
اگر به یک پیچیده تر نیاز داریم SchemaType
می توانیم ایجاد کنیم خود ما، اما خوب است اگر از قبل موجود است جستجو کنیم.
به عنوان مثال نشانی اینترنتی از نوع mongoose بسته سفارشی اضافه می کند SchemaType
که می توانستیم استفاده کنیم، mongoose.SchemaTypes.Url
.
ویژگی های مجازی
مجازی ها ویژگی های سندی هستند که در پایگاه داده ذخیره نمی شوند. آنها نتیجه یک محاسبه هستند. در مثال ما، قرار دادن نام کامل یک شخص در یک رشته به جای جدا کردن در مفید خواهد بود name
و surname
.
بیایید ببینیم که چگونه این کار را پس از تعریف اولیه طرحواره خود انجام دهیم:
PersonSchema.virtual('fullName').
get(function() {
if(this.surname)
return this.name + ' ' + this.surname;
return this.name;
}).
set(function(fullName) {
fullName = fullName.split(' ');
this.name = fullName(0);
this.surname = fullName(1);
});
ملک مجازی fullName
در بالا برای سادگی مواردی را مطرح می کند: هر شخصی حداقل یک نام یا نام و نام خانوادگی دارد. اگر فردی نام وسط یا نام یا نام خانوادگی داشته باشد با مشکل مواجه می شویم. تمام آن محدودیت ها را می توان در داخل آن رفع کرد get()
و set()
توابع تعریف شده در بالا
از آنجایی که مجازیها در پایگاه داده ذخیره نمیشوند، نمیتوانیم از آنها به عنوان فیلتر هنگام جستجوی افراد در پایگاه داده استفاده کنیم. در مورد ما باید استفاده کنیم name
و surname
.
میان افزار
میانافزار توابع یا قلابهایی هستند که میتوانند قبل یا بعد از روشهای استاندارد Mongoose اجرا شوند save()
یا find()
مثلا.
یک فرد می تواند یک mother
و الف father
. همانطور که قبلاً گفتیم، ما این روابط را با ذخیره شناسه شی به عنوان ویژگی های شخص ذخیره می کنیم، نه خود اشیا. خوب است که هر دو ویژگی را به جای ID فقط با خود اشیا پر کنید.
این را می توان به عنوان یک pre()
تابع مربوط به findOne()
روش مانگوس:
PersonSchema.pre('findOne', function(next) {
this.populate('mother').populate('father');
next();
});
تابع فوق باید تابع دریافت شده را به عنوان پارامتر فراخوانی کند. next()
به منظور ادامه پردازش قلاب های دیگر.
populate()
یک روش Mongoose برای جایگزینی شناسه ها با اشیایی است که آنها نشان می دهند، و ما از آن برای دریافت والدین در هنگام جستجوی تنها یک نفر استفاده می کنیم.
ما می توانیم این را اضافه کنیم hook به دیگر توابع جستجو، مانند find()
. اگر بخواهیم حتی میتوانیم والدین را به صورت بازگشتی پیدا کنیم. اما ما باید رسیدگی کنیم populate()
با دقت، زیرا هر تماس یک واکشی از پایگاه داده است.
یک مدل برای طرحواره ایجاد کنید
به منظور شروع ایجاد اسناد مبتنی بر روی طرح واره ما، آخرین مرحله کامپایل یک مدل مبتنی بر مدل است روی طرحواره:
const Person = mongoose.model('Person', PersonSchema);
اولین آرگومان، نام مفرد مجموعه ای خواهد بود که به آن اشاره می کنیم. این ارزشی است که ما به آن دادیم ref
دارایی از mother
و father
خواص شخص ما استدلال دوم این است Schema
قبلا تعریف کردیم
این model()
روش یک کپی از همه تعریف شده ایجاد می کند روی طرحواره همچنین شامل تمام متدهای Mongoose است که برای تعامل با پایگاه داده استفاده خواهیم کرد.
مدل تنها چیزی است که از هم اکنون به آن نیاز داریم روی. ما حتی می توانستیم استفاده کنیم module.exports
برای در دسترس قرار دادن شخص در سایر ماژول های برنامه ما:
module.exports.Person = mongoose.model('Person', PersonSchema);
module.exports.db = mongoose;
ما نیز صادر کردیم mongoose
مدول. قبل از پایان برنامه به آن نیاز داریم تا از پایگاه داده جدا شود.
ما میتوانیم import ماژول به این صورت:
const {db, Person} = require('./persistence');
روش استفاده از مدل
مدلی که در بخش آخر کامپایل کردیم، تمام آنچه را که برای تعامل با مجموعه نیاز داریم را شامل می شود روی پایگاه داده.
اکنون ببینیم که چگونه از مدل خود برای تمام عملیات CRUD استفاده می کنیم.
ایجاد افراد
ما میتوانیم یک شخص را با انجام کارهای زیر ایجاد کنیم:
let alice = new Person({name: 'Alice'});
این name
تنها ملک مورد نیاز است. بیایید شخص دیگری بسازیم اما این بار با استفاده از ویژگی مجازی:
let bob = new Person({fullName: 'Bob Brown'});
اکنون که دو نفر اول خود را داریم، میتوانیم یک نفر جدید با تمام ویژگیهای پر شده، از جمله والدین ایجاد کنیم:
let charles = new Person({
fullName: 'Charles Brown',
photosURLs: ('https://bit.ly/34Kvbsh'),
yearBorn: 1922,
notes: 'Famous blues singer and pianist. Parents not real.',
mother: alice._id,
father: bob._id,
});
همه مقادیر برای این نفر آخر روی مقادیر معتبر تنظیم میشوند، زیرا اعتبارسنجی به محض اجرای این خط با خطا مواجه میشود. به عنوان مثال، اگر URL عکس اول را روی چیزی غیر از پیوند تنظیم کرده بودیم، با این خطا مواجه می شدیم:
ValidationError: Person validation failed: photosURLs.0: wrong_url is not a valid URL
همانطور که قبلا توضیح داده شد، والدین به جای اشیا، شناسه دو نفر اول را تکمیل کردند.
ما سه نفر ایجاد کردهایم، اما هنوز در پایگاه داده ذخیره نشدهاند. در ادامه این کار را انجام می دهیم:
alice.save();
bob.save();
عملیاتی که شامل پایگاه داده می شود ناهمزمان هستند. اگر میخواهیم برای تکمیل صبر کنیم، میتوانیم از async/wait استفاده کنیم:
await charles.save();
اکنون که همه افراد در پایگاه داده ذخیره شدهاند، میتوانیم آنها را با استفاده از آن بازیابی کنیم find()
و findOne()
مواد و روش ها.
بازیابی یک یا چند نفر
همه متدهای Find در Mongoose نیاز به یک آرگومان برای فیلتر کردن جستجو دارند. بیایید آخرین فردی را که ایجاد کردیم برگردانیم:
let dbCharles = await Person.findOne({name: 'Charles', surname: 'Brown'}).exec();
findOne()
یک پرس و جو را برمی گرداند، بنابراین برای به دست آوردن نتیجه باید آن را با آن اجرا کنیم exec()
و سپس منتظر نتیجه با await
.
چون الف را ضمیمه کردیم hook به findOne()
روشی برای پر کردن والدین فرد، اکنون می توانیم مستقیماً به آنها دسترسی داشته باشیم:
console.log(dbCharles.mother.fullName);
در مورد ما می دانیم که پرس و جو فقط یک نتیجه را برمی گرداند، اما حتی اگر بیش از یک نفر با فیلتر مطابقت داشته باشد، تنها نتیجه اول برگردانده خواهد شد.
اگر از آن استفاده کنیم می توانیم بیش از یک نتیجه بگیریم find()
روش:
let all = await Person.find({}).exec();
آرایهای را برمیگردانیم که میتوانیم آن را تکرار کنیم.
به روز رسانی افراد
اگر قبلاً شخصی داریم، چه به این دلیل که آن را ایجاد کردهایم یا آن را بازیابی کردهایم، میتوانیم تغییرات را با انجام زیر بهروزرسانی و ذخیره کنیم:
alice.surname = 'Adams';
charles.photosURLs.push('https://bit.ly/2QJCnMV');
await alice.save();
await charles.save();
زیرا هر دو نفر از قبل وجود دارند روی در پایگاه داده، Mongoose فرمان به روز رسانی را فقط با تغییر فیلدها ارسال می کند، نه کل سند.
حذف اشخاص
مانند بازیابی، حذف را می توان برای یک یا چند نفر انجام داد. در ادامه این کار را انجام می دهیم:
await Person.deleteOne({name: 'Alice'});
await Person.deleteMany({}).exec();
پس از اجرای این دو دستور مجموعه خالی می شود.
نتیجه
در این مقاله دیدیم که چگونه Mongoose می تواند در پروژه های NodeJS و MongoDB ما بسیار مفید باشد.
در اکثر پروژه های MongoDB ما نیاز داریم که داده ها را با فرمت مشخصی ذخیره کنیم. خوب است بدانید که Mongoose یک راه آسان برای مدلسازی و اعتبارسنجی آن دادهها ارائه میکند.
نمونه پروژه کامل را می توان یافت روی GitHub.
(برچسبها برای ترجمه)# جاوا اسکریپت
منتشر شده در 1403-01-19 20:12:04