Далее добавим зависимость ConfigModule.forRoot() в корневой модуль, которая позволит нам во всём проекте использовать один и тот же файл конфигурации (глобализирует модуль forRoot). Она позволит нам работать с переменными окружения.
src / app.module.ts
Записываем какое-либо значение в переменные окружения.
.env
И уже в любом другом нужном нам модуле мы можем заинжектить этот сервис по работе с переменными окружения и воспользоваться его функционалом: получить значение переменной можно с помощью функции get(), которая принимает в себя наименование переменной.
После установки докера, нужно настроить его окружение под наш проект:
version - минимальная версия докера
services - сервисы, которые используются в данном контейнере
image - образ, который запускает контейнер
container_name - имя контейнера
restart - перезапуск каждый раз, когда у нас перезагрузился сервер
environment - переменные окружения (логин и пароль администратора)
ports - позволяет прокинуть порт изнутри контейнера наружу (без них не получится подключиться к БД)
volumes - позволяет подключить часть дискового пространства внутри контейнера к диску на сервере (компьютере)
command - команды (ограничение кеша для БД)
docker-compose.yml
Позволяет поднять контейнер по заданным параметрам (по файлу docker-compose.yml в папке, где запускается команда):
Позволяет посмотреть контейнеры | выбираем отдельный контейнер монги:
Примечание: grep работает только на unix-системах
Так же посмотреть на статус контейнера можно через десктопное приложение докера
Остановить и запустить контейнер мы можем следующими комадами:
003 Подключение Mongo
Сейчас нам нужно установить данные модули:
mongoose - удобная ORM для монги
typegoose - позволяет проще описать модели для mongoose
nestjs-typegoose - позволяет использовать typegoose в несте более нативно (приближенно к основным подходам фреймворка)
Записываем переменные для подключения к монге в окружение
.env
Далее, в основном модуле приложения, подключим модуль провайдера монги TypegooseModule
Тут мы используем вместо forRoot метод forRootAsync, который позволит асинхронно инициализировать модуль вместе с его зависимостями. Это делается для того, чтобы иметь возможность использовать ConfigModule в зависимостях модуля тайпгуза
Для того, чтобы использовать любой провайдер, нужно использовать модуль, который содержит этот провайдер, поэтому вставляем в import модуль ConfigModule
В inject мы вставляем зависимость из ConfigModule, а именно тут это представляет ConfigService, который позволит нам получить данные из .env
Внутрь useFactory будет помещать функцию, которая сгенерирует строку подключения к БД монги getMongoConfig.
src / app.module.ts
Сейчас нам нужно написать саму функцию getMongoConfig, которая сгенерирует параметры подключения.
Таким образом должен выглядеть объект подключения по типам:
Все конфиги, которые мы передаём в модули, лучше складировать в папку configs.
getMongoConfig - эта функция возвращает объект, который содержит в себе строку подключения к монге и деструктурированный объект, возвращаемый из функции, которая возвращает опции монги
getMongoString - возвращает строку подключения к монге через обращение к configService
getMongoOptions - возвращает опции для подключения к монге
src / configs / mongo.config.ts
И теперь npm start запустит наш сервер с подключением к монге
004 Подключение моделей
Далее нам нужно подготовить наши модели данных и навесить на них декораторы, чтобы typegoose понял, как работать с этими данными
В модуль нужно импортировать TypegooseModule, из которого буде использовать локальную функциональность (forFeature), в которой опишем модель данных, которую будет иметь данный модуль
src > auth > auth.module.ts
Далее нам нужно описать свойства (а именно, их характеристики), которые будут попадать в монгу через декораторы
@prop - описывает данные как отдельные свойства, которые будут класться в базу. Данный декоратор стоит добавлять на все свойства, которые мы отправляем в монгу.
Ну и так же далее нам нужно сделать TimeStamps, который будет помечать время создания объекта. Можно создать его отдельным свойством (createdAt), а можно сделать правильно и расширить ДТОшку от тайпгуза через extends TimeStamp
Вместе с этим нужно добавить ещё и _id в нашу модель. Это можно сделать ещё более красивым способом - заэкстендить интерфейс с именем класса модели данных от класса Base. И тут нужно будет сказать, что в наши модели данных теперь нельзя добавлять поле _id, так как оно присутствует в Base. Сам интерфейс обязательно нужно экспортировать, чтобы TS смог смёрджить класс и интерфейс
src > auth > auth.model.ts
Чтобы пустые интерфейсы не подсвечивались, нужно их оффнуть в еслинте
Добавляем ровно то же самое подключение Typegoose модуля для подключение модели к модулю продукта
src > product > product.module.ts
Если мы хотим в @prop указать тип, то нам придётся указать такую конструкцию:
Между [] попадает не тип TypeScript, а конструктор типа Typegoose
Типизация модели продукта:
src > product > product.model.ts
Подключение модуля тайпгуза к обзору:
src > review > review.module.ts
Типизация модели обзора:
src > review > review.model.ts
Подключение модуля главной страницы:
src > top-page > top-page.module.ts
Типизация модели главной страницы:
src > top-page > top-page.model.ts
Если бы мы присвоили значения для свойства енама, то можно было бы указать и возвращаемый тип
И теперь тут отображены после кор-модуля все 4 модуля forFeature, которые мы подключили к модулям приложения
005 Сервис отзывов
Добавляем новый сервис через CLI неста
Далее добавляется в модуль зависимость от данного сервиса в провайдерах
Далее переходим в сервис и первым делом в конструкторе инжектим ReviewModel, который предоставит доступ к редактированию данных внутри данной модели (предоставит доступ к методам изменения, создания и так далее)
src > review > review.service.ts
Так же нам нужно добавить в модель обзора id продукта, к которому будет присвоен комментарий
src > review > review.model.ts
Далее нам нужно описать ДТОшку модели данных, которую нужно соблюдать для создании нового обзора на продукт
src > review > dto > create-review.dto.ts
И далее подставим для контроллера создания новую ДТОшку, которая будет отвечать за модель принимаемых данных для добавления обзора
src > review > review.controller.ts
Приступаем к описанию сервиса, который будет напрямую взаимодействовать с провайдером (хранить методы для модификации и изменения данных):
create - метод создания нового обзора
findByProductId - метод поиска обзора по продукту (для вывода обзоров по продукту)
delete - удаление обзора
deleteByProductId - удаление обзоров по id продукта (например, если удалится продукт, то вместе с ним и обзор)
Конкретно reviewModel предоставляет нам методы для работы с данными внутри Mongo:
find - найти запись по query, которая принимает в себя объект с полями {}
create - создание нового объекта по модели данных
findByIdAndDelete - поиск и удаление записи по id
deleteMany - удаление нескольких записей по query
В некоторых операциях используется метод exec, который запускает операцию
Когда мы пишем в query productId: new Types.ObjectId(productId), то тут мы вызываем поиск по новому созданному типу, который является уникальным идентификатором для записи
src > review > review.service.ts
И далее в контроллере (который принимает в себя запросы с фронта) вызываем методы сервиса, который уже и производит изменения в базе данных
Сюда в конструктор вставляем ReviewService из review.service.ts.
Далее нам остаётся только добавить методы из сервиса ReviewService.
Наименования методов ровно такие же, как и в сервисе.
Сам контроллер работает только с http-запросами. Ответы на ошибки приходят тоже из него (тот же нестовский HttpException, который отправляет на фронт ответ со сгенерированной ошибкой)
src > review > review.controller.ts
Тут же мы храним константы, которые используются в модуле. Конкретно здесь хранится текстовый ответ, который придёт на фронт с ошибкой