Node.js + MongoDB: первая коллекция из приложения

Зачем связывать Node.js и MongoDB

MongoDB хорошо ложится на JavaScript-мышление: данные хранятся документами, похожими на обычные объекты. Поэтому связка Node.js + MongoDB часто встречается в учебных проектах, прототипах, админках, ботах, небольших API и MVP

Но есть тонкость. Новичок часто думает: "Раз MongoDB хранит JSON-подобные документы, значит можно просто кидать туда любые объекты". Технически можно, но лучше сразу привыкать к аккуратной структуре, проверке входных данных и хранению секретов вне кода

В этом уроке сделаем коллекцию leads и Express API для добавления и чтения заявок

Что получится в конце

Проект:

node-mongodb-api/
  package.json
  server.js
  db.js
  .env

Маршруты:

  • GET /api/status — проверка подключения;
  • GET /api/leads — список заявок;
  • POST /api/leads — добавление заявки.

Что нужно заранее

Нужны:

  • Node.js LTS;
  • npm;
  • MongoDB локально или MongoDB Atlas;
  • базовое понимание Express;
  • инструмент для проверки HTTP-запросов.

Для локального MongoDB connection string часто выглядит так:

mongodb://127.0.0.1:27017

Для Atlas строка будет длиннее и с логином/паролем

Создаем проект

mkdir node-mongodb-api
cd node-mongodb-api
npm init -y
npm install express mongodb dotenv

Пакеты:

  • express — сервер;
  • mongodb — официальный Node.js driver;
  • dotenv — переменные окружения.

Настройки в .env

Создайте .env:

MONGODB_URI=mongodb://127.0.0.1:27017
MONGODB_DB=solo_lessons
PORT=3000

Если используете Atlas, не публикуйте connection string с паролем. Для статьи можно показать шаблон, но не реальный секрет

Подключение к базе

Создайте db.js:

const { MongoClient } = require('mongodb');

const client = new MongoClient(process.env.MONGODB_URI);

let database;

async function connectToDatabase() {
  if (database) {
    return database;
  }

  await client.connect();
  database = client.db(process.env.MONGODB_DB);

  return database;
}

module.exports = {
  connectToDatabase
};

Мы не создаем новое подключение на каждый запрос. Один раз подключаемся и переиспользуем базу

Первый server.js

require('dotenv').config();

const express = require('express');
const { connectToDatabase } = require('./db');

const app = express();
const port = Number(process.env.PORT || 3000);

app.use(express.json());

app.get('/api/status', async (req, res, next) => {
  try {
    const db = await connectToDatabase();

    await db.command({ ping: 1 });

    res.json({
      ok: true,
      database: process.env.MONGODB_DB
    });
  } catch (error) {
    next(error);
  }
});

app.listen(port, () => {
  console.log(`API запущен: http://localhost:${port}`);
});

Запуск:

node server.js

Проверка:

curl http://localhost:3000/api/status

Если ответ ok: true, подключение работает

Добавляем документ в коллекцию

Добавим POST /api/leads:

app.post('/api/leads', async (req, res, next) => {
  try {
    const { name, email, source } = req.body;

    if (!name || !email) {
      return res.status(400).json({
        ok: false,
        message: 'Нужны name и email'
      });
    }

    const db = await connectToDatabase();
    const collection = db.collection('leads');

    const lead = {
      name,
      email,
      source: source || 'site',
      status: 'new',
      createdAt: new Date()
    };

    const result = await collection.insertOne(lead);

    res.status(201).json({
      ok: true,
      lead: {
        id: result.insertedId,
        ...lead
      }
    });
  } catch (error) {
    next(error);
  }
});

Проверка:

curl -X POST http://localhost:3000/api/leads \
  -H "Content-Type: application/json" \
  -d '{"name":"Анна","email":"anna@example.com","source":"landing"}'

MongoDB сама создаст базу и коллекцию при первой записи, если их еще не было

Читаем список документов

app.get('/api/leads', async (req, res, next) => {
  try {
    const db = await connectToDatabase();
    const collection = db.collection('leads');

    const leads = await collection
      .find({})
      .sort({ createdAt: -1 })
      .limit(50)
      .toArray();

    res.json({
      ok: true,
      leads
    });
  } catch (error) {
    next(error);
  }
});

Проверка:

curl http://localhost:3000/api/leads

Если заявка появилась в массиве, API работает

Полный server.js

require('dotenv').config();

const express = require('express');
const { connectToDatabase } = require('./db');

const app = express();
const port = Number(process.env.PORT || 3000);

app.use(express.json());

app.get('/api/status', async (req, res, next) => {
  try {
    const db = await connectToDatabase();

    await db.command({ ping: 1 });

    res.json({
      ok: true,
      database: process.env.MONGODB_DB
    });
  } catch (error) {
    next(error);
  }
});

app.get('/api/leads', async (req, res, next) => {
  try {
    const db = await connectToDatabase();
    const collection = db.collection('leads');

    const leads = await collection
      .find({})
      .sort({ createdAt: -1 })
      .limit(50)
      .toArray();

    res.json({
      ok: true,
      leads
    });
  } catch (error) {
    next(error);
  }
});

app.post('/api/leads', async (req, res, next) => {
  try {
    const { name, email, source } = req.body;

    if (!name || !email) {
      return res.status(400).json({
        ok: false,
        message: 'Нужны name и email'
      });
    }

    const db = await connectToDatabase();
    const collection = db.collection('leads');

    const lead = {
      name,
      email,
      source: source || 'site',
      status: 'new',
      createdAt: new Date()
    };

    const result = await collection.insertOne(lead);

    res.status(201).json({
      ok: true,
      lead: {
        id: result.insertedId,
        ...lead
      }
    });
  } catch (error) {
    next(error);
  }
});

app.use((error, req, res, next) => {
  console.error(error);

  res.status(500).json({
    ok: false,
    message: 'Внутренняя ошибка сервера'
  });
});

app.listen(port, () => {
  console.log(`API запущен: http://localhost:${port}`);
});

Важные привычки с MongoDB

Не хранить секреты в коде

Connection string с паролем должен жить в .env или настройках хостинга

Не принимать любой объект без проверки

MongoDB гибкая, но API должен быть строгим. Если заявке нужны name и email, проверяйте их

Ограничивать выдачу

В примере стоит .limit(50). Без лимита можно случайно вернуть слишком много документов

Думать об индексах

Когда коллекция растет, запросы по email, статусу или дате лучше поддерживать индексами

Не путать _id и id

MongoDB создает _id. В ответе API можно вернуть его как id, но внутри базы это ObjectId

Частые ошибки

MongoServerSelectionError

Приложение не может подключиться к MongoDB. Проверьте, запущен ли сервер, верный ли MONGODB_URI, открыта ли сеть для Atlas

Неверный пароль в Atlas

Проверьте пользователя базы, пароль, IP allowlist и правильность connection string

MONGODB_URI undefined

Не подключен dotenv или файл .env лежит не в корне проекта. В server.js должна быть строка:

require('dotenv').config();

Даты выглядят странно

new Date() хранит дату в формате, удобном для машины. Для вывода пользователю форматируйте дату отдельно

Ответы на эти вопросы могут быть для вас полезными

MongoDB лучше MySQL для Node.js?

Не лучше и не хуже, а другая. MongoDB удобна для документов и гибкой структуры. MySQL удобен для таблиц, связей и строгой схемы

Нужно ли использовать Mongoose?

Не обязательно. Для первого понимания полезно начать с официального драйвера MongoDB. Mongoose можно изучить позже, когда понадобится схема и модели

Можно ли использовать MongoDB локально?

Да. Для учебы локальная MongoDB подходит. Для облачного старта часто используют MongoDB Atlas

Почему коллекция появилась сама?

MongoDB может создать базу и коллекцию при первой записи. Это удобно, но не отменяет проектирование структуры данных

Как удалить тестовые документы?

Можно использовать MongoDB Compass, shell или отдельный route в учебном проекте. В реальном API удаление лучше делать с авторизацией

Что почитать дальше по Node.js

Если вы собираете тему по шагам, рядом лучше открыть:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x