Plugins — mongoose-paginate, mongoose-unique-validator
Muammodan boshlaylik
Loyihada 12 ta model. Har birida bir xil narsalar:
- Sahifalash:
skip,limit,countDocuments,sahifalarhisoblash — 12 marta nusxalangan createdBy,updatedBymaydonlari va ularni to'ldirish- Soft delete:
ochirilganmaydoni vafinddagi filtr
Bitta joyda xato tuzatilsa — qolgan 11 tasida qoladi.
Plugin nima?
Plugin — schema ga maydonlar, metodlar, middleware va boshqa imkoniyatlarni qayta ishlatiladigan tarzda qo'shuvchi funksiya.
function plugin(schema, options) {
// schema ni kengaytirish
}
mahsulotSchema.plugin(plugin, { ...opsiyalar })
Hayotiy o'xshatma
Telefon uchun g'ilof va qo'shimcha batareya. Telefon (schema) o'zi ishlaydi, lekin unga tayyor qo'shimcha kiyib, yangi imkoniyat olasiz. Bir xil g'ilofni bir xil modeldagi har qanday telefonga kiyish mumkin — har biri uchun alohida yasash shart emas.
O'z plaginingiz
Vaqt va muallif
// src/plugins/muallif.js
export function muallifPlugin(schema) {
schema.add({
yaratdi: { type: schema.base.Schema.Types.ObjectId, ref: 'User', immutable: true },
ozgartirdi: { type: schema.base.Schema.Types.ObjectId, ref: 'User' },
})
schema.methods.muallifniBelgila = function (userId) {
if (this.isNew) this.yaratdi = userId
this.ozgartirdi = userId
return this
}
}
import { muallifPlugin } from '../plugins/muallif.js'
mahsulotSchema.plugin(muallifPlugin)
postSchema.plugin(muallifPlugin)
const m = new Mahsulot(malumot)
await m.muallifniBelgila(req.user.id).save()
Sahifalash
// src/plugins/sahifalash.js
export function sahifalashPlugin(schema, { maxHajm = 50 } = {}) {
schema.statics.sahifala = async function (filtr = {}, { sahifa = 1, hajm = 20, sort = { _id: -1 }, select } = {}) {
sahifa = Math.max(1, Number(sahifa) || 1)
hajm = Math.min(maxHajm, Math.max(1, Number(hajm) || 20))
const [royxat, jami] = await Promise.all([
this.find(filtr).select(select).sort(sort).skip((sahifa - 1) * hajm).limit(hajm).lean(),
this.countDocuments(filtr),
])
return {
royxat,
jami,
sahifa,
hajm,
sahifalar: Math.ceil(jami / hajm),
keyingisiBor: sahifa * hajm < jami,
}
}
}
mahsulotSchema.plugin(sahifalashPlugin, { maxHajm: 100 })
const natija = await Mahsulot.sahifala({ kategoriya: 'telefon' }, { sahifa: req.query.sahifa, sort: { narx: 1 } })
Global plugin
Barcha schema larga:
import mongoose from 'mongoose'
import { sahifalashPlugin } from './plugins/sahifalash.js'
mongoose.plugin(sahifalashPlugin) // modellar yaratilishidan OLDIN
[!WARNING]
mongoose.plugin()faqat undan keyin yaratilgan modellarga ta'sir qiladi. Uni ilovaning eng boshida, modellar import qilinishidan oldin chaqiring.
mongoose-paginate-v2
Tayyor sahifalash plagini:
npm install mongoose-paginate-v2
import mongoosePaginate from 'mongoose-paginate-v2'
mahsulotSchema.plugin(mongoosePaginate)
const natija = await Mahsulot.paginate(
{ kategoriya: 'telefon' },
{
page: 2,
limit: 20,
sort: { narx: 1 },
select: 'nomi narx rasm',
populate: { path: 'sotuvchi', select: 'ism' },
lean: true,
}
)
{
docs: [ ... ],
totalDocs: 348,
limit: 20,
page: 2,
totalPages: 18,
hasNextPage: true,
hasPrevPage: true,
nextPage: 3,
prevPage: 1
}
Javob maydonlarini o'zbekchalashtirish — customLabels: { docs: 'royxat', totalDocs: 'jami' }. Aggregation uchun — mongoose-aggregate-paginate-v2.
mongoose-unique-validator
unique: true xatosi (E11000) — ValidationError emas va boshqa validatsiya xatolari bilan birga kelmaydi (41-dars). Plagin uni oddiy validatsiya xatosiga aylantiradi:
npm install mongoose-unique-validator
import uniqueValidator from 'mongoose-unique-validator'
userSchema.plugin(uniqueValidator, { message: '{PATH} "{VALUE}" allaqachon band' })
// ValidationError: email: email "lola@mail.uz" allaqachon band
[!INFO] Plagin saqlashdan oldin qo'shimcha so'rov bilan tekshiradi — bu poyga holatidan (race condition) himoya qilmaydi. Index baribir kerak va
11000xatosi baribir kelishi mumkin. Plagin faqat qulay xabar uchun. Plaginning Mongoose versiyangizga mosliginipackage.jsondagipeerDependenciesdan tekshiring.
Boshqa foydali plaginlar
| Plagin | Vazifasi |
|---|---|
mongoose-lean-virtuals |
lean() da virtual lar (45-dars) |
mongoose-delete |
Soft delete (57-dars) |
mongoose-autopopulate |
ref larni avtomatik populate |
mongoose-sequence |
Avtomatik o'suvchi raqam (buyurtmaRaqami: 1001) |
mongoose-slug-updater |
Slug yasash |
[!TIP] Har bir plagin — qo'shimcha bog'liqlik va "yashirin" xatti-harakat. Oddiy narsalar uchun (sahifalash, muallif) o'z 20 qatorli plaginingiz ko'pincha yaxshiroq: siz uni to'liq tushunasiz va Mongoose yangilanganda u buzilmaydi.
Tez-tez uchraydigan xatolar
Plagin ni modeldan keyin ulash
const Mahsulot = mongoose.model('Mahsulot', mahsulotSchema)
mahsulotSchema.plugin(mongoosePaginate) // ❌ kech
autopopulate bilan cheksiz sikl
User → Post → User... avtomatik populate zanjiri. Chuqurlikni cheklang yoki aniq populate ishlating.
Eskirgan plaginlar
Ko'p eski plaginlar yangi Mongoose bilan ishlamaydi (remove hook, callback lar). O'rnatishdan oldin oxirgi yangilanish sanasini tekshiring.
Xulosa
- Plugin — schema ni kengaytiruvchi qayta ishlatiladigan funksiya:
schema.plugin(fn, opts) - Ichida:
schema.add,schema.methods,schema.statics,schema.pre - Global —
mongoose.plugin(), modellardan oldin mongoose-paginate-v2— tayyor sahifalash:Model.paginate(filtr, opts)mongoose-unique-validator—11000ni chiroyli xabarga; index baribir kerak- Oddiy ehtiyojlar uchun — o'z plaginingiz
Keyingi dars: 49-dars — Mongoose bilan Aggregation Pipeline