MongoDB — mongoose, schema, model, CRUD

~25 daq · Express · Ma'lumotlar Bazasi

MongoDB nima va PostgreSQL dan farqi?

PostgreSQL va MySQL — relyatsion ma'lumotlar bazasi. Ma'lumotlar jadvalda saqlanadi, qat'iy tuzilma bor, har ustunning turi oldindan belgilanadi.

MongoDB — hujjatli (document) ma'lumotlar bazasi. Ma'lumotlar JSON ga o'xshash hujjatlar sifatida saqlanadi. Qat'iy tuzilma yo'q — har hujjatda turli maydonlar bo'lishi mumkin.

Qachon MongoDB? Tuzilma tez-tez o'zgaradigan loyihalarda, ichma-ich ma'lumotlar ko'p bo'lganda (blog posti + izohlar + teglar — bitta hujjatda), prototip va MVP larda.

Qachon PostgreSQL? Murakkab so'rovlar, transaksiyalar, qat'iy ma'lumot yaxlitligi kerak bo'lganda.


Mongoose nima?

MongoDB ni Node.js dan to'g'ridan-to'g'ri ishlatish mumkin — rasmiy mongodb driver bor. Lekin u past darajali: schema yo'q, validatsiya yo'q, hamma narsa qo'lda.

Mongoose — MongoDB ustiga qurilgan kutubxona. U qo'shadi:

  • Schema — hujjat qanday ko'rinishi kerakligini belgilash
  • Validatsiya — ma'lumot to'g'riligini tekshirish
  • Model — schema asosida CRUD operatsiyalari

Hayotiy o'xshatma: MongoDB — bo'sh qog'oz, istalgan narsani yozish mumkin. Mongoose — shakl (forma), faqat belgilangan joylarni to'ldirish mumkin.

npm install mongoose

Ulanish

// db.js
const mongoose = require('mongoose');

async function connectDB() {
  try {
    await mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/mydb');
    console.log('MongoDB ga ulandi');
  } catch (err) {
    console.error('MongoDB ga ulanib bo\'lmadi:', err.message);
    process.exit(1);
  }
}

module.exports = connectDB;
// app.js
const connectDB = require('./db');
connectDB(); // server ishga tushganda ulanish

Schema — hujjat tuzilmasini belgilash

Schema — "bu kolleksiyada hujjatlar qanday ko'rinishi kerak" degan qoida. Maydonlar, turlari, validatsiya — hammasi shu yerda.

// models/User.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema(
  {
    name: {
      type:     String,
      required: [true, 'Ism majburiy'],
      trim:     true,       // bosh va oxiridagi bo'shliqlarni o'chirish
      minlength: [2, 'Ism kamida 2 ta harf'],
    },
    email: {
      type:     String,
      required: [true, 'Email majburiy'],
      unique:   true,
      lowercase: true,      // kichik harfga aylantirish
      match:    [/^\S+@\S+\.\S+$/, 'Email noto\'g\'ri formatda'],
    },
    age: {
      type: Number,
      min:  [0,   'Yosh manfiy bo\'lmasligi kerak'],
      max:  [120, 'Yosh 120 dan oshmasligi kerak'],
    },
    role: {
      type:    String,
      enum:    ['user', 'admin'],
      default: 'user',
    },
  },
  {
    timestamps: true, // createdAt va updatedAt avtomatik qo'shiladi
  }
);

timestamps: true — juda qulay. Har hujjatga createdAt va updatedAt avtomatik qo'shiladi va yangilanadi.


Model — schema dan yaratiladi

Schema — qoida. Model — o'sha qoida asosida ma'lumotlar bazasi bilan ishlash uchun ob'ekt.

const User = mongoose.model('User', userSchema);

module.exports = User;

'User' — model nomi. Mongoose bu nomdan kolleksiya nomini hosil qiladi: users (kichik harf, ko'plik). Siz users kolleksiyasini qo'lda yaratmasangiz ham — Mongoose o'zi yaratadi.


CRUD

const express = require('express');
const router  = express.Router();
const User    = require('../models/User');

// CREATE
router.post('/', async (req, res, next) => {
  try {
    const user = await User.create(req.body);
    res.status(201).json(user);
  } catch (err) {
    next(err);
  }
});

// READ — hammasi
router.get('/', async (req, res, next) => {
  try {
    const users = await User.find().select('-__v'); // __v — versiya maydoni, kerak emas
    res.json(users);
  } catch (err) {
    next(err);
  }
});

// READ — bittasi
router.get('/:id', async (req, res, next) => {
  try {
    const user = await User.findById(req.params.id);
    if (!user) return res.status(404).json({ message: 'Topilmadi' });
    res.json(user);
  } catch (err) {
    next(err);
  }
});

// UPDATE
router.patch('/:id', async (req, res, next) => {
  try {
    const user = await User.findByIdAndUpdate(
      req.params.id,
      req.body,
      { new: true, runValidators: true } // new: yangilangan hujjatni qaytarish
    );
    if (!user) return res.status(404).json({ message: 'Topilmadi' });
    res.json(user);
  } catch (err) {
    next(err);
  }
});

// DELETE
router.delete('/:id', async (req, res, next) => {
  try {
    const user = await User.findByIdAndDelete(req.params.id);
    if (!user) return res.status(404).json({ message: 'Topilmadi' });
    res.status(204).send();
  } catch (err) {
    next(err);
  }
});

module.exports = router;

{ new: true } — findByIdAndUpdate standart bo'yicha eski hujjatni qaytaradi. new: true bilan — yangilangan hujjat qaytariladi.

runValidators: true — update da ham schema validatsiyasi ishlaydi. Standart bo'yicha update da validatsiya ishlamaydi — bu kutilmagan xatti-harakat.


Xato boshqarish — Mongoose xatolari

Mongoose o'ziga xos xatolar chiqaradi. Error middleware da ularni ushlab, tushunarli javob berish kerak:

app.use((err, req, res, next) => {
  // Mongoose validatsiya xatosi
  if (err.name === 'ValidationError') {
    const messages = Object.values(err.errors).map(e => e.message);
    return res.status(400).json({ message: messages.join(', ') });
  }

  // Noto'g'ri ID formati (ObjectId)
  if (err.name === 'CastError') {
    return res.status(400).json({ message: 'Noto\'g\'ri ID formati' });
  }

  // Unique constraint
  if (err.code === 11000) {
    const field = Object.keys(err.keyValue)[0];
    return res.status(409).json({ message: `${field} allaqachon mavjud` });
  }

  console.error(err.stack);
  res.status(500).json({ message: 'Server xatosi' });
});

Tez-tez uchraydigan xatolar

{ new: true } unutish:

const user = await User.findByIdAndUpdate(id, { name: 'Yangi' });
res.json(user); // eski ma'lumot qaytariladi!

runValidators: true unutish:

await User.findByIdAndUpdate(id, { age: -5 });
// Validatsiya ishlamaydi — -5 saqlanadi

Noto'g'ri ID bilan findById:

await User.findById('noto\'g\'ri-id');
// CastError: Cast to ObjectId failed
// Error middleware da ushlanishi kerak

Xulosa

MongoDB — hujjatli ma'lumotlar bazasi, qat'iy tuzilma yo'q. Mongoose — schema, validatsiya va model bilan ishlashni osonlashtiradi.

Schema — hujjat tuzilmasini belgilaydi. Model — schema asosida CRUD operatsiyalari. timestamps: true — createdAt va updatedAt avtomatik.

{ new: true, runValidators: true } — update da har doim qo'shiladi.


Keyingi dars

17-dars: Redis — ioredis, cache, TTL