Обработчик обновления CouchDB/cloudant не работает должным образом

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

{
  "_id": "_design/_updateHandler",
  "updates": {
    "in-place": "function(doc, req) {
        var field = req.body.field,
        var value= req.body.value,
        var doc[field] = value;
        return [doc, toJSON(doc)];
    }"
  }
}

И он добавляет поле в документ, но не обновляет существующее поле. Это ожидаемое поведение? Это не выглядит так ни в облачной документации для обработчиков обновлений, ни в документация couchdb.

Если нет, как я могу решить эту проблему, чтобы обновить существующее поле? Кроме того, как указано в этом вопросе, функция обработчика обновления все равно получит конфликт обновления, но как его избежать?

Заранее спасибо :)


person oxente    schedule 25.02.2016    source источник
comment
Советую вам механизм консультативного замка; или повторите попытку при конфликте. Для консультативного замка; вы можете просто использовать memcache/redis; или в словаре памяти; или заблокировать документ в cloudant. Для повторного использования метода conflich; просто повторно примените свои изменения при конфликтной ошибке (http 409).   -  person Safak Ulusoy    schedule 27.02.2016
comment
Код примера, который вы вставили, содержит множество ошибок... запятые после операторов var, var doc, когда документ уже определен, и т. д. :( У вас есть более новый код? Или код ближе к тому, что вы пытаетесь? Вы можете протестировать функцию на это собственная консоль вашего браузера, чтобы сначала очистить JS.   -  person BigBlueHat    schedule 04.03.2016
comment
Кроме того, пример в CouchDB Docs легче повторять, чем пример в вики: docs.couchdb.org/en/1.6.1/couchapp/ddocs.html#update-functions   -  person BigBlueHat    schedule 04.03.2016


Ответы (1)


Вот рабочий пример функции обновления, совместимой с CouchDB и Cloudant, которая выполняет то, что вам нужно, — обновляет одно поле.

function(doc, req) {
  if (!doc) doc = {_id: req.uuid};
  var body = JSON.parse(req.body);
  var field = body.field;
  var value = body.value;
  doc[field] = value;
  return [doc, JSON.stringify(doc)];
}

Тело запроса POST считается действительным JSON, поэтому вы можете выполнить некоторые проверки заголовка для application/json.

Кроме того, если вы планируете использовать только поле = значение, как здесь, то application/x-www-form-url-encoded будет лучше, так как это уменьшит размер полезной нагрузки и время синтаксического анализа — CouchDB и Cloudant автоматически преобразуют этот тип мультимедиа в объект req.form.

Наконец, лучше никогда не ставить префикс подчеркивания к чему-либо, что вы даете CouchDB или Cloudant, поскольку он считается зарезервированным символом в начале полей верхнего уровня и значений _id. Имя _design/_updateHandler (впоследствии) очень запутанное...

Вот JSON для копирования/вставки в вашу базу данных, чтобы получить работающую функцию обновления, которая делает то, что вы хотели:

{
    "_id": "_design/overwrite",
    "updates": {
        "in-place": "function(doc, req) {\n  if (!doc) doc = {_id: req.uuid};\n  var body = JSON.parse(req.body);\n  var field = body.field;\n  var value = body.value;\n  doc[field] = value;\n  doc.body = body;\n  return [doc, JSON.stringify(doc)];\n}"
    }
}

Чтобы обновить существующий документ, вы должны сделать HTTP-запрос, подобный этому (где bigbluehat — это _id ранее сохраненного документа:

POST /db/_design/overwrite/_update/in-place/bigbluehat
Content-Type: application/json

{"field": "name", "value": "BigBlueHat"}

Или, если вы не включите документ _id в URL-адрес запроса, вы получите новый документ, который использует значение req.uuid для хранения нового документа.

Надеюсь, это поможет!

person BigBlueHat    schedule 03.03.2016
comment
Спасибо, что указали на ошибки в коде! Я расстроился из-за конфликтов и остановился на этом коде, где ничего не произошло. У меня все еще есть проблемы с лучшим способом разрешения конфликтов. Прямо сейчас я использую решение Safak Ulusoy, но оно кажется неправильным. Есть ли лучший способ решить эту проблему? - person oxente; 04.03.2016
comment
Забыл упомянуть... Очень полезные советы! - person oxente; 04.03.2016
comment
Конфликты — это не обязательно плохо. :) Это просто зависит от того, почему они происходят, можете ли вы спроектировать вокруг (или для!) Их, и какова основная причина этого - слишком частые обновления одного документа, который на самом деле должен храниться в нескольких документах. ? (неправильное) использование CouchDB для чего-то, в чем Redis лучше (подсчет в памяти)? и т. д. Может быть, опубликовать еще один вопрос и пропинговать меня. ^_^ - person BigBlueHat; 04.03.2016