MongoDB / Mongoose CRUD

Mongoose CRUD

Mongoose-ийн Model нь MongoDB-ийн бүх CRUD үйлдлийг дэмждэг — гэхдээ driver-аас хялбар, TypeScript-тэй нягт нийцтэй. Энэ хичээлд нийтлэг методуудыг жишээтэйгээр авч үзнэ.

Model.create() — үүсгэх

typescript
import User from "./models/User";

// Нэг document үүсгэх
const user = await User.create({
  username: "bold_bataa",
  email: "bold@example.com",
  xp: 0,
});

console.log(user._id); // ObjectId автоматаар үүссэн
console.log(user.createdAt); // timestamps: true — автоматаар орсон

// Олон document нэгэн зэрэг үүсгэх
const users = await User.create([
  { username: "dorj", email: "dorj@example.com" },
  { username: "od", email: "od@example.com" },
]);

find() — олон document хайх

typescript
// Бүгдийг авах
const allUsers = await User.find();

// Нөхцөлтэй хайх
const activeUsers = await User.find({ role: "user" });

// Projection + sort + limit
const topUsers = await User.find({}, { username: 1, xp: 1 })
  .sort({ xp: -1 })
  .limit(10);

// $gte, $lt зэрэг operator-ууд ижил хэвээр
const seniorUsers = await User.find({ xp: { $gte: 500 } });

findById() — ID-аар нэг document хайх

typescript
const user = await User.findById("64abc1234567890123456789");

if (!user) {
  throw new Error("Хэрэглэгч олдсонгүй");
}

console.log(user.username);

findOne() — нэг document хайх

typescript
// И-мэйлээр хайх
const user = await User.findOne({ email: "bold@example.com" });

// Олдохгүй бол null буцна
if (!user) {
  return res.status(404).json({ error: "Хэрэглэгч олдсонгүй" });
}

findByIdAndUpdate() — ID-аар шинэчлэх

typescript
// new: true — шинэчлэгдсэн document-ийг буцаана (анхдагч: хуучин document)
const updated = await User.findByIdAndUpdate(
  userId,
  { $inc: { xp: 10 }, $set: { lastActive: new Date() } },
  { new: true, runValidators: true },
);

// runValidators: true — Schema validation-ийг update-д ч ажиллуулна

findByIdAndDelete() — ID-аар устгах

typescript
const deleted = await User.findByIdAndDelete(userId);

if (!deleted) {
  throw new Error("Устгах document олдсонгүй");
}

populate() — reference холбох

ref тавигдсан ObjectId талбарыг populate ашиглан бодит document-ээр солино — $lookup-ийн Mongoose хувилбар:

typescript
// Post schema-д authorId: { type: Schema.Types.ObjectId, ref: "User" }
const post = await Post.findById(postId).populate("authorId");

console.log(post.authorId.username); // ObjectId биш — бодит User object

Populate-д projection нэмж болно — хэрэгтэй талбаруудаа л авах:

typescript
const post = await Post.findById(postId).populate(
  "authorId",
  "username email -_id",
); // зөвхөн username, email

Олон талбарыг populate хийх:

typescript
const post = await Post.findById(postId)
  .populate("authorId", "username")
  .populate("comments.userId", "username");

Middleware — pre/post hook

Mongoose middleware нь тодорхой үйлдлийн өмнө (pre) эсвэл дараа (post) код ажиллуулдаг.

pre("save") — хадгалахаас өмнө

typescript
import bcrypt from "bcrypt";

// Нууц үг хадгалахаас өмнө hash хийх
userSchema.pre("save", async function (next) {
  // Зөвхөн password өөрчлөгдсөн үед hash хий
  if (!this.isModified("password")) return next();

  this.password = await bcrypt.hash(this.password, 10);
  next();
});

post("save") — хадгалсаны дараа

typescript
// Шинэ хэрэглэгч бүртгэгдсэний дараа welcome и-мэйл илгээх
userSchema.post("save", async function (doc) {
  await sendWelcomeEmail(doc.email, doc.username);
});

pre("findOneAndDelete") — устгахаас өмнө

typescript
// Хэрэглэгч устгагдахад тухайн хэрэглэгчийн нийтлэлүүдийг ч устгах
userSchema.pre("findOneAndDelete", async function (next) {
  const userId = this.getQuery()._id;
  await Post.deleteMany({ authorId: userId });
  next();
});

Бүрэн жишээ: Express route

typescript
import express from "express";
import User from "../models/User";
import Post from "../models/Post";

const router = express.Router();

// GET /users/:id — хэрэглэгч + нийтлэлүүд
router.get("/:id", async (req, res) => {
  try {
    const user = await User.findById(req.params.id).select("-password"); // password хасах

    if (!user) {
      return res.status(404).json({ error: "Хэрэглэгч олдсонгүй" });
    }

    const posts = await Post.find({ authorId: user._id })
      .sort({ createdAt: -1 })
      .limit(5)
      .select("title createdAt");

    res.json({ user, recentPosts: posts });
  } catch (error) {
    res.status(500).json({ error: "Серверийн алдаа" });
  }
});

// PATCH /users/:id/xp — XP нэмэх
router.patch("/:id/xp", async (req, res) => {
  const user = await User.findByIdAndUpdate(
    req.params.id,
    { $inc: { xp: 10 } },
    { new: true },
  );
  res.json({ xp: user?.xp, level: user?.level });
});

export default router;

Дараагийн хичээлд:

MongoDB болон Mongoose-ийг production-д ашиглахад мөрдөх шилдэг туршлагуудыг үзнэ.