Основной ответ
Структурируйте свои POST / PUTs для документа, поле которого вы хотите сохранить уникальным, следующим образом:
Создать представление . В функции map используйте поле, которое вы хотите применить уникальным, как key . Ценность может быть ничем. Используйте функцию уменьшения , чтобы получить счетчик для каждого из ваших ключей. Лучший способ (для производительности) - использовать встроенную _count функцию уменьшения.
Сразу после того, как вы PUT / POST новый документ в базе данных, захватите возвращенные id
и rev
и GET / yourdb / _design / yourapp / _view / ViewName? группа = истина и ключ = " стоимость из-вашего-уникального поля-с шагом-1 ".
Если результат последнего GET даст вам значение счетчика, отличное от 1 , то вы просто вставили дубликат. Немедленно УДАЛИТЬ /yourdb/id-from-step-2?rev=rev-from-step-2.
Relax .
Грубый пример
Допустим, вы храните учетные записи пользователей и хотите, чтобы адрес электронной почты был уникальным, но вы не хотите делать его идентификатором документа (по какой-либо причине). Создайте представление, чтобы быстро проверить уникальность адреса электронной почты, как описано выше. Давайте назовем это emails . Он будет иметь функцию карты , возможно, похожую на эту ...
function(doc) {
if(doc.type === 'account') {
emit(doc.email, 1);
}
}
И просто _count
как функция уменьшения . Если вы излучаете 1 , как указано выше, _sum
также будет работать. Наличие и проверка поля type
на вашем документе, как показано выше, - это просто соглашение, но иногда я нахожу его полезным. Если все, что вы храните, это учетные записи пользователей, вам, вероятно, это не нужно.
Теперь предположим, что мы вставляем документ следующим образом ...
POST /mydb/
{
"name": "Joe",
"email": "joe@example.org"
}
И CouchDB ответит что-то вроде ...
{
ok: true,
id: 7c5c249481f311e3ad9ae13f952f2d55,
rev: 1-442a0ec9af691a6b1690379996ccaba6
}
Проверьте, есть ли у нас более одного joe@example.org в базе данных ...
GET /mydb/_design/myapp/_view/emails/?group=true&key="joe@example.org"
И CouchDB ответит чем-то вроде ...
{
rows: [
{
key: "joe@example.org",
value: 1
}
]
}
Если value
отличается от 1
в этом ответе, вы, вероятно, просто вставили дубликат электронной почты. Поэтому удалите документ и верните сообщение об ошибке в виде строки Адрес электронной почты должен быть уникальным , аналогичным типичному ответу базы данных SQL или как вам угодно.
Удаление будет выглядеть примерно так ...
DELETE /mydb/7c5c249481f311e3ad9ae13f952f2d55?rev=1-442a0ec9af691a6b1690379996ccaba6
Краткое обсуждение (если вам интересно)
Если вы пришли из старого доброго * фона SQL, это будет казаться неправильным и странным. Перед тем, как скинуть, рассмотрите эти моменты. Наличие ограничения на поле, такого как уникальность или что-либо еще, подразумевает схему . CouchDB без схемы .
Исходя из * SQL означает, что вам придется изменить способ мышления. ACID и Locks - не единственный способ. CouchDB обладает большой гибкостью и мощью. То, как вы используете это, чтобы получить то, что вы хотите, будет зависеть от деталей вашего варианта использования и от того, насколько хорошо вы сможете выйти за пределы традиционного мышления реляционных баз данных.
Причина, по которой я иногда реализую уникальность таким образом, заключается в том, что она очень мягкая для меня. Если вы думаете о том, как CouchDB работает с обработкой конфликтов обновления и т. Д., Этот подход следует той же последовательности. Мы храним документ, который нам дали, затем проверяем, является ли наше поле уникальным. Если нет, то возьмите тот документ, который мы только что вставили, с помощью удобного дескриптора, который у нас есть, и сделайте что-нибудь, чтобы устранить потребность в уникальности, например, удалив его.
В приведенном выше примере может возникнуть искушение проверить уникальность адреса электронной почты до you POST
doc. Быть осторожен!! Если происходит несколько событий, возможно, что другой документ с тем же адресом электронной почты может быть вставлен в базу данных в момент после , когда вы проверяете, существует ли электронная почта, но до вы сделай свой POST
! Это оставит вас с дубликатом электронной почты.
Нет ничего плохого в том, что вы также проверяете адрес электронной почты перед вами POST
. Например, это хорошая идея, если ваш пользователь заполняет форму и вы можете отправить значение поля электронной почты в базу данных. Вы можете заранее предупредить пользователя о том, что адрес электронной почты существует, или запретить отправку и т. Д. Однако во всех случаях вам следует также всегда проверять уникальность после вас POST
док. Затем реагируйте по мере необходимости. С точки зрения пользовательского интерфейса, вышеприведенные шаги не будут отличаться от результата, полученного от традиционной * базы данных SQL, использующей ограничение уникальности.
Что-нибудь может пойти не так? Да. Учти это. Предположим, что joe@example.org еще не существует в базе данных. Два документа приходят почти одновременно и сохраняются в базе данных. Документ A равен POSTed
, затем Документ B равен POSTed
, но прежде чем мы сможем проверить уникальность Документ A POST
. Итак, теперь, когда мы выполняем проверку уникальности для Doc A POST
, мы видим, что joe@example.org находится в базе данных дважды. Итак, мы удалим его и сообщим о проблеме. Но, скажем, прежде чем мы сможем удалить Doc A , также выполняется проверка уникальности для Doc B , получая то же значение счетчика для joe@example.org. Теперь оба POSTs
будут отклонены, хотя joe@example.org изначально не было в базе данных! Другими словами, если два документа с совпадающим значением входят в ваше приложение практически одновременно, возможно может видеть друг друга POSTs
и ошибочно заключить, что значение, которое они несут, уже находится в база данных! Мы не можем реально предотвратить это, потому что в CouchDB нет традиционного стиля RDB блокировка . Но в обмен на эту небольшую цену мы получаем реплику мастер-мастер и массу других интересных вещей. Я возьму это! И если это огромная проблема для вашей реализации, вы можете попытаться решить ее, внедрив некоторый механизм повторов и т. Д.
Наконец, CouchDB действительно является жемчужиной базы данных, но не просто примите это и ожидайте, что это будет пуленепробиваемый подход. Многое будет зависеть от деталей вашего конкретного приложения.