Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Node.js
Code

Пакетный импорт CSV - файла в MongoDB при помощи Mongoose и Node.js

by
Length:MediumLanguages:
This post is part of a series called An Introduction to Mongoose for MongoDB and Node.js.
An Introduction to Mongoose for MongoDB and Node.js

Russian (Pусский) translation by AlexBioJS (you can also view the original English article)

Final product image
What You'll Be Creating

Рад, что могу обсудить эту тему. Во многих веб-приложениях довольно часто происходит получение пользовательских данных и сохранение единственной записи в вашу базу данных. Но что если ваши пользователи (или вы сами) хотят выполнить массовую вставку одной командой?

Читайте статью далее, чтобы узнать, как создавать шаблон CSV (comma-separated values - значения, разделённые запятыми) - файла и форму для загрузки CSV - файла и как осуществить парсинг CSV - файла для создания модели Mongoose, которую сохраним в базу данных MongoDB.

Предполагается, что у вас есть базовые представления о Mongoose и ее взаимодействии с MongoDB. Если же их нет, то я предлагаю вам для начала прочитать мою статью Введение в Mongoose для MongoDB и Node.js. В ней рассказывается, как Mongoose взаимодействует с MongoDB путем создания строго-типизированных схем, из которых создается модель. Если вы уже хорошо понимаете Mongoose, поехали дальше.

Начало работы

Для начала давайте создадим новое приложение Node.js. Перейдите в командной строке в директорию, куда вы хотите установить ваше приложение Node.js, и выполните следующие команды:

Я оставил значения по умолчанию как есть, поэтому мое приложение запустится при помощи файла index.js. Сперва, до создания и парсинга CSV - файлов, нам необходимо осуществить первоначальные настройки. Я хочу сделать веб-приложение. Для этого я собираюсь поручить выполнение всех основных настроек сервера модулю Express. Для установки Express выполните в консоли следующую команду:

Так как наше веб-приложение будет принимать файлы при помощи веб-формы, я собираюсь также использовать подмодуль Express Express File Upload. Давайте теперь установим и его:

Этой первоначальной конфигурации достаточно, чтобы установить моё веб-приложение и создать базовую веб-страницу с формой для загрузки файлов на сервер.

Ниже приведен мой index.js, в котором устанавливается мой веб-сервер:

В этом примере мы подключаем модули Express и Express File Upload, настраиваем веб-приложение на использование File Upload и прослушиваем подключения на 80 порту. Также в данном примере мы создали с помощью Express маршрут для обработки запросов к "/", по которому будет отсылаться целевая страница по умолчанию  моего веб-приложения. В ответ на запросы по этому пути отправляется файл index.html, содержащий веб-форму, которая позволяет пользователю закачать CSV - файл. Поскольку приложение работает на моем локальном компьютере, то в моём случае при переходе на http://localhost я увижу форму, которую создам в следующем примере.

Ниже приведена моя страница index.htm с формой для закачивания CSV - файла:

В данном HTML-файле есть два важных момента:

  1. Ссылка на "/template", при клике которой будет скачан шаблон CSV - файла, который можно заполнить информацией, которую необходимо отправить.
  2. Форма, свойству encType которой присвоено значение multipart/form-data, и поле для ввода типа file, которое принимает файлы с расширением "csv".

Как вы могли заметить, HTML-файл ссылается на шаблон Author. Если вы читали мою статью 'Введение в Mongoose...', то помните, что я создал схему Author. В этой статье я собираюсь воссоздать эту схему и создать для пользователя возможность массового импорта коллекции авторов в мою базу данных MongoDB. Давайте посмотрим на схему Author. Однако, вы, вероятно, догадались, что сначала нам необходимо установить модуль Mongoose:

Создание схемы и модели

Теперь, когда у нас установлен Mongoose, давайте создадим новый файл author.js, в котором определим схему и модель Author:

Теперь, когда у нас созданы схема и модель Author, давайте переключимся и сосредоточимся на создании шаблона CSV - файла, который можно скачать, кликнув по ссылке шаблона. Для упрощения генерации шаблона CSV - файла я собираюсь использовать модуль JSON (JavaScript Object Notation - текстовый формат обмена данными, основанный на JavaScript) to CSV. Давайте теперь установим его:

Теперь я собираюсь обновить мой заранее созданный файл index.js, чтобы добавить новый маршрут для обработки запросов к "/template":

Я привел только новый код для маршрута шаблона, который добавляем в предыдущий файл index.js.

В коде происходит следующее: подключение нового файла template.js (будет создан следующим) и создание  маршрута для обработки запросов к "/template". При запросах к пути этого маршрута будет вызвана функция get в файле template.js.

Теперь, когда у нас обновлен сервер Express добавлением нового маршрута, давайте создадим новый файл template.js:

В этом файле я сначала подключаю предварительно установленный модуль json2csv. Затем создаю и экспортирую функцию get. Эта функция принимает в качестве аргументов объекты запроса и ответа от сервера Express.

Внутри функции я создал массив полей, которые хочу использовать в моем шаблоне CSV - файла. Создать список полей можно различными способами. Первый (которым я воспользовался в этом примере) - это создание статического списка полей, которые необходимо включить в шаблон. Второй - это динамическое создание списка полей путем извлечения свойств из схемы Author.

Второй способ можно было бы осуществить при помощи следующего кода:

Я бы захотел использовать этот динамический метод, если бы не трудности, которые возникают, если я не хочу включать множество свойств из схемы в шаблон CSV - файла. В моём примере в шаблоне не используются свойства _id и created, так как их значения будут заданы с помощью кода. Однако, если у вас нет полей, которые вы хотите исключить, то динамический способ также подходит.

Создание шаблона CSV - файла

После определения массива полей я использую модуль json2csv для создания из объекта JavaScript шаблона CSV - файла. Этот объект csv будет результатом запросов к маршруту с путем '/template'.

И, наконец, используя свойство res сервера Express, я устанавливаю значения двух заголовков, что обеспечит скачивание файла authors.csv.

Если бы вы запустили ваше Node-приложение на данном этапе и перешли в своем веб-браузере по ссылке http://localhost, то на экране отобразилась бы веб-форма со ссылкой для скачивания шаблона. Кликнув по ссылке для скачивания шаблона, вы скачаете файл authors.csv для заполнения перед закачиванием.

Ниже приведен пример заполненного CSV - файла:

В результате закачивания этого шаблона будет создано два автора: я и мой друг, который написал книгу о Node.js несколько лет назад. Вы, наверное, заметили, что в конце каждой строки расположены три запятые ", , ,". Это сделано для сокращения примера. Я не заполнил свойства социальных сетей (twitter, facebook и linkedin).

Кусочки мозаики начинают собираться в единое целое и формировать общую картину. Давайте перейдем к самому важному нашего примера и осуществим парсинг CSV - файла. Нам необходимо немного обновить файл index.js для подключения к MongoDB и создания нового маршрута для обработки запросов POST, по которому на сервер загружается файл.

После подключения к базе данных и настройки нового маршрута для обработки запросов POST пришло время осуществить парсинг CSV - файла. К счастью, для этого есть несколько отличных библиотек. Я решил использовать модуль fast-csv, который вы можете установить при помощи следующей команды:

Маршрут для обработки запросов POST был создан подобно маршруту шаблона. В нем вызывается функция post из файла upload.js. Нет необходимости помещать функции маршрутов в разные файлы.Однако, мне хочется сделать разные файлы для этих маршрутов, поскольку это помогает поддерживать читабельность и организованность кода.

Отправка данных

И, наконец, давайте создадим файл upload.js, в котором содержится функция post, которую вызываем после отправки заранее созданной формы:

Довольно много происходит в этом файле. В первых трех строках мы подключаем необходимые модули, которые понадобятся для осуществления парсинга и сохранения данных CSV - файла.

Далее определяется и экспортируется функция post для использования в файле index.js. Именно внутри этой функции происходит волшебство.

Сначала функция проверяет наличие файла в теле запроса. Если файл отсутствует, то возвращается ошибка, указывающая, что необходимо закачать файл.

Когда файл закачан, ссылка на файл сохраняется в переменную с именем authorFile благодаря обращению к массиву files и свойству file этого массива. Имя свойства file соответствует имени поля для отправки файла, которое я указал в примере index.html.

Также я создал массив authors, который будет наполняться по мере того как осуществляется парсинг CSV - файла. Этот массив будет использоваться для сохранения данных в базу данных.

Далее вызывается библиотека fast-csv при использовании ее функции fromString. Функция принимает CSV - файл в виде строки. Я извлек строку из свойства authorFile.data. В свойстве data находится содержимое моего закачанного CSV - файла.

Я передал две опции в функцию fromString модуля  fast-csv: headers и ignoreEmpty. Значениями обоих является true. Это сообщает библиотеке, что в первой строке CSV - файла будут содержаться заголовки и что необходимо игнорировать пустые строки.

Теперь, когда опции настроены, я определил две функции слушателей событий, которые вызываются при генерировании событий data и end. Событие data генерируется один раз для каждой строки CSV - файла. В этом событии содержится объект JavaScript данных, подвергшихся парсингу.

Я обновляю этот объект для включения свойства _id схемы Author с новым значением типа ObjectId (уникальный идентификатор объекта, первичный ключ, _id). Далее этот объект добавляется в массив authors.

После того, как осуществился парсинг всего CSV - файла, генерируется событие end. Внутри функции обратного вызова для этого события я вызываю функцию create модели Author, передавая ей массив authors.

Если при сохранении массива происходит ошибка, то выкидывается исключение. В ином случае пользователю отображается сообщение о количестве авторов, закачанных и сохраненных в базу данных.

На случай, если бы вы хотели увидеть весь исходный код, я создал репозиторий GitHub с кодом.

Заключение

В моём примере я закачал только несколько записей. Если в вашем случае необходима закачка тысяч записей, то было бы неплохо сохранять записи небольшими частями.

Это можно осуществить различными способами. Если бы мне нужно было это реализовать, то я бы предложил обновить функцию обратного вызова, зарегистрированную на событие data, добавив проверку длины массива authors.  При превышении длины массива установленной вами длины, например, 100, вызовите функцию Author.create для этого массива и затем сбросьте (присвойте значение 0) массив.  Затем функция сохранит записи частями по 100. Убедитесь, что оставили последний вызов функции create в функции обратного вызова, зарегистрированной на событие end, для сохранения конечных записей.

Наслаждайтесь!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.