#5 Рефакторим работу с Mongoclient

poster
В этом уроке мы реализуем добавление и удаление исполнителей в базе данных. Порефакторим работу с базой данных, создав отдельный модуль для работы с Mongoclient
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

В этом видео мы закончим рефакторить наше API добавив методы put и delete. Также мы порефакторим работу с базой данных, вынеся ее в отдельный файл.

Итак давайте добавим сначала put метод.

app.put('/artists/:id', function (req, res) {
  db.collection('artists').updateOne(
    { _id: ObjectID(req.params.id) },
    { name: req.body.name },
    function (err, result) {
      if (err) {
        console.log(err);
        return res.sendStatus(500);
      }
      res.sendStatus(200);
    })
})

Здесь мы вызываем updateOne на коллекцию исполнителей. Первым аргументом идет обьект с полями, по которым мы ищем елемент, который хотим обновить. Вторым аргументом идет обьект данных, которые мы хотим обновить и третьим идет callback, где мы проверяем успешно ли мы обновили запись и если все хорошо, то возвращаем статус 200.

Delete реализовывается по тому же принципу

app.delete('/artists/:id', function (req, res) {
  db.collection('artists').deleteOne(
    { _id: ObjectID(req.params.id) },
    function (err, result) {
      if (err) {
        console.log(err);
        return res.sendStatus(500);
      }
    res.sendStatus(200);
  })
})

Здесь мы применяем deleteOne на коллекцию. Первым аргументом идет обьект с полями по которым мы ищем елемент, а вторым callback, где мы возвращаем success или error.

Мы закончили с вами реализацию API на nodejs, но у нас сервер уже занимает 100 строчек и чем больше мы будем реализовывать, тем сложнее его будет поддерживать. Давайте разобьем его на несколько файлов.

Для начала мы можем вынести работу с базой данных в отдельный файл. Мы хотим, чтобы мы могли работать с базой из любого файла написав

var db = require('./db');

Давайте создадим новый файл db.js и реализуем обетку вокруг метода connect. Мы хотим, чтобы он работал так же как и раньше, но сохранял в локальную переменную db. Также мы хотим, чтобы connect был синглтоном, если коннект к базе у нас уже есть, то мы не открываем еще один коннект а возвращаем существующий.

var MongoClient = require('mongodb').MongoClient;

var state = {
  db: null
};

exports.connect = function (url, done) {
  if (state.db) {
    return done();
  }

  MongoClient.connect(url, function (err, db) {
    if (err) {
      return done(err);
    }
    state.db = db;
    done()
  });
}

Теперь давайте заменим код коннекта в server.js на нашу реализацию.

var db = require('./db');
db.connect('mongodb://localhost:27017/api', function (err, database) {
  if (err) {
    return console.log(err);
  }
  app.listen(3012, function () {
    console.log('API app started');
  })
})

Мы убрали весь код, который записывал базу данных в переменную и саму переменную из server.js. Наш код стал немного чище.

Если мы перезапустим сейчас наш сервер, то connect будет работать правильно, но db.collection будет бросать ошибку, так как такого метода у нас нет. Давайте добавим метод get, который будет возвращать db, с которой мы сможем работать.

exports.get = function () {
  return state.db;
}

Теперь все места, где мы используем db.collection нам нужно заменить на db.get().collection.

db.get().collection('artists')
Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
Игорь Бадьин
5 месяцев назад
Будет ли работать с PostgreSQL без изменений кода в файле server.js, описанная в данном уроке абстракция для db? Мне кажется, что нет, потому что интерфейсы у mongo и PostgreSQL для доступа к данным разные.
monsterlessons
5 месяцев назад
Нет не будет. Потому что это и не планировалось. Эту абстракцию мы писали для более удобного доступа к монге.
LocKtaR-o-DarK
6 месяцев назад
лечится добавлением в метод connect вторым параметром { useNewUrlParser: true }
LocKtaR-o-DarK
6 месяцев назад
большое спасибо за урок вы в исходниках забыли в одном месте там где метод findOne после db добавить .get() для mongodb version v4.0.5 (думаю и с 3 вылечится) в начале файла db.js объявим var dbName = 'myapi'; тогда в методе .connect надо сделать так state.db = db.db(dbName); и будет все работать единственное, смущает: DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect. но это уже мелочи
Codename CobWeb
2 лет назад
Интересно почему с 3 версией mongodb пишет что db.get() not function, а с твоим кодом и 2й версией все хорошо.
monsterlessons
2 лет назад
Потому что создатели всех библиотек (за исключением, может, React) обожают менять API с каждой новой версией. Им кажется, что это клево.
Codename CobWeb
2 лет назад
Покапался, вообщем для версии драйвера "mongodb": "^3.0.1", подойдут следующие решения. 1) Тут как решить проблему с db.get() not function (https://stackoverflow.com/questions/47662220/db-collection-is-not-a-function-when-using-mongoclient-v3-0?noredirect=1&lq=1) 2) С put трабла тоже была пока не сделал так ( app.put('/artists/:id', function (req, res) { db.get().collection('artists').updateOne( { _id: ObjectID(req.params.id) }, { $set: {name: req.body.name} }, { upsert: false }, function (err, result) { if (err) { console.log(err); return res.sendStatus(500); } res.sendStatus(200); } ) }) )
monsterlessons
2 лет назад
Спасибо, что написали. Думаю это поможет всем, кто устанавливает 3 версию.
Rustam Apaev
2 лет назад
большое спасибо за урок. А чтобы не делать всё это вручную , может порекомендуешь какие-то готовые шаблоны? где всё это уже сделано и осталось пользоваться ) Больше всего меня в бэкенде вопрос авторизации смущает, вроде такая приземленная вещь (которую никто не оценит), но много надо корпеть над ней. (извиняюсь, что вышел за рамки этого видео)
monsterlessons
2 лет назад
На здоровье. Как ORM для ноды из популярных - это mongoose и sequelize, но они достаточно низкоуровневые. Готового фреймворка нет и не предвидится. Для авторизации чаще всего используют passport + дополнительные пакеты (passport-local, passport-oauth). Но опять же оно дает базовые функционал и все обертки нужно писать руками. В ноде все тлен в этом плане)) Из хороших фрейморков для бекенда, где все эти вещи сделаны на нужном уровне и там нужно писать руками намного меньше я бы посоветовал ruby + ruby on rails.
Rustam Apaev
2 лет назад
а так я с метеором знаком... но некоторые вещи пока не смог реализовать в нём. в руби я уже не полезу, наверное