Эта статья - вторая часть по созданию приложения CRUD с помощью Express и MongoDB. Мы собираемся углубиться в две последние операции, которые не были рассмотрены в первой части - ОБНОВЛЕНИЕ и УДАЛЕНИЕ.

Без лишних слов приступим ко второй части.

CRUD - ОБНОВЛЕНИЕ

Операция ОБНОВЛЕНИЕ используется, когда вы хотите что-то изменить. Он может быть активирован только браузерами с помощью запроса PUT. Как и запрос POST, запрос PUT может быть запущен с помощью JavaScript или элемента ‹form›.

Давайте попробуем запустить запрос PUT через JavaScript на этот раз, поскольку мы уже узнали, как инициировать запрос через элемент ‹form› при прохождении запроса POST в предыдущем статья.

Для целей этого урока мы собираемся создать кнопку, при нажатии на которую будет заменена последняя цитата, написанная мастером Йодой, цитатой, написанной Дартом Вейдером.

Для этого мы сначала добавляем кнопку в файл index.ejs:

<div>
  <h2>Replace last quote written by Master Yoda with a quote written by Darth Vadar</h2>
  <button id="update"> Darth Vadar invades! </button>
</div>

Мы также собираемся создать внешний файл JavaScript для выполнения запроса PUT при нажатии кнопки. Согласно соглашениям Express, этот файл помещается в папку с именем public.

$ mkdir public
$ touch public/main.js

Затем мы должны сказать Express, чтобы эта общедоступная папка стала общедоступной с помощью встроенного промежуточного программного обеспечения под названием express.static.

app.use(express.static('public'))

Как только это будет сделано, мы можем добавить файл main.js в файл index.ejs:

<!-- ... -->
<script src="main.js"></script>
</body>

Затем мы отправим запрос PUT при нажатии кнопки:

// main.js
var update = document.getElementById('update')
update.addEventListener('click', function () {
  // Send PUT Request here
})

Самый простой способ вызвать запрос PUT в современных браузерах - использовать Fetch API. Он поддерживается только в Firefox, Chrome и Opera, поэтому вы можете использовать polyfill, если хотите использовать Fetch в реальном проекте.

Мы собираемся отправить на сервер следующий запрос на выборку. Взгляните на это быстро, и я объясню, что все это значит:

fetch('quotes', {
  method: 'put',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    'name': 'Darth Vader',
    'quote': 'I find your lack of faith disturbing.'
  })
})

Готовы понять, почему запрос Fetch написан именно так? :)

Fetch принимает два параметра. Первый параметр - это путь. В этом случае мы отправляем запрос на / quote, который будет обрабатываться на нашем сервере.

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

Мы устанавливаем «метод» на «поставить», потому что мы отправляем запрос PUT.

Заголовки здесь относятся к заголовкам HTTP, которые вы хотите отправить на сервер. Это объект с несколькими парами "ключ-значение".

«Тело» относится к контенту, который вы отправляете на сервер.

Вы можете заметить, что мы установили Content-Type на application / json. Мы также преобразовали цитату Дарта Вейдера в текст JSON с помощью JSON.stringify. Мы выполняем эти шаги, потому что отправляем цитату Дарта Вадара в формате JSON (стандартный формат для отправки информации в Интернете) на сервер.

К сожалению, наш сервер еще не считывает данные JSON. Мы можем научить его читать данные JSON с помощью промежуточного программного обеспечения bodyparser.json ():

app.use(bodyParser.json())

Как только мы сделаем все, что описано выше, мы сможем обработать этот запрос PUT с помощью метода put:

app.put('/quotes', (req, res) => {
  // Handle put request 
})

Следующий шаг - научиться искать последнюю цитату Мастера Йоды и заменять ее цитатой Дарта Вейдера в MongoDB.

Обновление коллекции в MongoDB

Коллекции MongoDB поставляются с методом findOneAndUpdate, который позволяет нам изменять один элемент из базы данных. Он принимает четыре параметра - запрос, обновление, параметры и обратный вызов.

db.collections('quotes').findOneAndUpdate(
  query, 
  update, 
  options,
  callback
)

Первый параметр, query, позволяет нам фильтровать коллекцию по заданным парам "ключ-значение". Мы можем отфильтровать коллекцию цитат для цитат мастера Йоды, задав имя Йода.

{
  name: 'Yoda'
}

Второй параметр, update, сообщает MongoDB, что делать с запросом на обновление. Он использует операторы обновления MongoDB, такие как $ set, $ inc и $ push. Мы будем использовать оператор $ set, поскольку мы заменяем цитаты Йоды на цитаты Дарта Вейдера:

{
  $set: {
    name: req.body.name,
    quote: req.body.quote
  }
}

Третий параметр, options, - необязательный параметр, позволяющий определять дополнительные параметры. Поскольку мы ищем последнюю цитату Йоды, мы установим для сортировки в параметрах значение {_id: -1}. Это позволяет MongoDB выполнять поиск в базе данных, начиная с самой новой записи.

{
  sort: {_id:-1}
}

Есть вероятность, что в нашей базе нет цитат мастера Йоды. Когда это происходит, MongoDB по умолчанию ничего не делает. Мы можем заставить его создать новую запись, если мы установим для параметра upsert, что означает вставку (или сохранение), если записи не найдены, значение true:

{
  sort: {_id: -1},
  upsert: true
}

Последний параметр - это функция обратного вызова, которая позволяет вам что-то делать после того, как MongoDB заменит последнюю цитату Йоды цитатой Дарта Вадара. В этом случае мы можем отправить результаты обратно в запрос на выборку.

(err, result) => {
  if (err) return res.send(err)
  res.send(result)
}

Вот вся команда findOneAndUpdate, которую мы написали за несколько предыдущих шагов:

app.put('/quotes', (req, res) => {
  db.collection('quotes')
  .findOneAndUpdate({name: 'Yoda'}, {
    $set: {
      name: req.body.name,
      quote: req.body.quote
    }
  }, {
    sort: {_id: -1},
    upsert: true
  }, (err, result) => {
    if (err) return res.send(err)
    res.send(result)
  })
})

Теперь, когда кто-то нажимает кнопку обновления, браузер отправляет запрос PUT через Fetch на наш сервер Express. Затем сервер отвечает, отправляя измененную цитату обратно для выборки. Затем мы можем обработать ответ внутри, связав выборку с методом then. Это возможно, потому что Fetch возвращает объект Promise.

Правильный способ проверить, успешно ли разрешена выборка - использовать метод ok для объекта ответа. Затем вы можете вернуть res.json (), если хотите прочитать данные, которые были отправлены с сервера:

fetch({ /* request */ })
.then(res => {
  if (res.ok) return res.json()
})
.then(data => {
  console.log(data)
})

Если вы работаете над модным веб-приложением, это та часть, где вы используете JavaScript для обновления DOM, чтобы пользователи могли сразу увидеть новые изменения. Обновление DOM выходит за рамки этой статьи, поэтому мы просто обновим браузер, чтобы увидеть изменения.

fetch({ /* request */ })
.then(res => {
  if (res.ok) return res.json()
})
.then(data => {
  console.log(data)
  window.location.reload(true)
})

Готово к операции CREATE! Перейдем к последнему - УДАЛИТЬ.

CRUD - УДАЛИТЬ

Операцию DELETE можно запустить только с помощью запроса DELETE. Он похож на запрос ОБНОВЛЕНИЕ, поэтому он прост, если вы понимаете, что мы сделали ранее.

В этой части давайте научимся удалять первую цитату Дарта Вейдера. Для этого сначала нужно добавить кнопку в файл index.ejs.

<div>
  <h2>Delete Darth Vader's first quote</h2>
  <button id="delete"> Delete first Darth Vader quote </button>
</div>

Затем мы будем вызывать запрос DELETE через Fetch при каждом нажатии кнопки удаления:

var del = document.getElementById('delete')
del.addEventListener('click', function () {
  fetch('quotes', {
    method: 'delete',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      'name': 'Darth Vader'
    })
  })
  .then(res => {
    if (res.ok) return res.json()
  }).
  then(data => {
    console.log(data)
    window.location.reload()
  })
})

Затем мы можем обработать событие на нашей стороне сервера с помощью метода удаления:

app.delete('/quotes', (req, res) => {
  // Handle delete event here
})

Удаление записи в MongoDB

Коллекции MongoDB поставляются с методом findOneAndDelete, который позволяет нам удалить один элемент из базы данных. Он принимает три параметра - запрос, параметры и обратный вызов. Эти параметры точно такие же, как те, которые мы использовали в findOneAndUpdate при обновлении записи в MongoDB. Единственная разница здесь в том, что в вариантах нет никаких апсертов.

db.collections('quotes').findOneAndDelete(
  query, 
  options,
  callback
)

Помните, мы пытаемся удалить первую цитату Дарта Вейдера. Для этого мы фильтруем коллекцию цитат по имени «Дарт Вейдер». Таким образом, параметр запроса:

{
  name: req.body.name
}

Мы можем пропустить параметр options, поскольку нам не нужно менять порядок сортировки на обратный. Затем мы можем отправить ответ на запрос Fetch в функции обратного вызова.

(err, result) => {
  if (err) return res.send(500, err)
  res.send('A darth vader quote got deleted')
})

Полный код обработчика удаления выглядит следующим образом:

app.delete('/quotes', (req, res) => {
  db.collection('quotes').findOneAndDelete({name: req.body.name}, 
  (err, result) => {
    if (err) return res.send(500, err)
    res.send('A darth vader quote got deleted')
  })
})

Теперь, когда кто-то нажимает кнопку удаления, браузер отправляет запрос DELETE через Fetch на наш сервер Express. Затем сервер отвечает, отправляя либо сообщение об ошибке, либо сообщение.

Как и раньше, мы можем перезагрузить веб-сайт, когда выборка будет успешно завершена.

fetch({ /* request */ })
.then(res => {
  if (res.ok) return res.json()
})
.then(data => {
  console.log(data)
  window.location.reload(true)
})

На этом операция УДАЛИТЬ!

Заключение

Теперь вы узнали все, что вам нужно знать о создании простых приложений с помощью Node и MongoDB. Теперь идите вперед и создайте больше приложений, молодой падаван. Да прибудет с тобой сила.