Стратегия репликации CouchDB с динамическими группами пользователей
Это ситуация:
У нас есть ряд пользователей, которые делятся некоторыми документами. Документы, которыми они могут поделиться, могут меняться в течение дня, так же как и сами документы (изменения и удаления). Пользователи могут изменять некоторую информацию в документах.
Например
Пользователи | документы
A | Икс
A | Y
A | Z
Б | Икс
Б | Z
C | Y
Возможные группы: A+C, A+B
Сервер на CouchDB является копией базы данных SQL Server с этими данными, ETL заботится об управлении изменениями на CouchDB. Однако база данных CouchDB реплицируется на каждый телефон пользователя через PouchDB.
Цель:
Копировать изменения и удаления соответственно.
Что мы пробовали:
1) мы решили структурировать наши документы со списком пользователей, которые могут получить к нему доступ. Каждый документ будет иметь массив "Пользователи", а затем фильтр в проектном документе будет заботиться о репликации для клиентов. К сожалению, удаления документов и изменения документов, которые не проходят фильтр (например, пользователь удаляется из массива), не присутствуют в фиде _changes, поэтому не могут быть соответствующим образом реплицированы на клиентах.
2) база данных на пользователя. Это невозможно, потому что пользователи должны видеть, как другие работают над документами (они делятся ими)
3) база данных на группу пользователей. Практически та же проблема, что и в первом решении, но хуже. По факту:
- группы пользователей могут меняться и больше не присутствовать: как это отражается на стороне клиента?
- документ может быть перенесен в новую группу: его нужно будет заново загрузить с нуля. Это значительно увеличивает размер загрузки
- один и тот же документ может быть в нескольких группах! (см. пример выше)
- каждый клиент должен знать, в какую группу он входит каждый раз, когда он входит в систему, и реплицировать несколько баз данных. Затем в обратном путешествии вы должны будете знать, в каких базах данных присутствовал документ
Есть ли рецепт для такой ситуации? Я упускаю очевидное решение?
РЕДАКТИРОВАТЬ
Частичное решение для случая 1:
localDB.sync(remoteDB, {
live: true,
retry: true,
filter: 'app/by_user',
query_params: { "agente": agent }
})
.on('paused', function(info){
console.log("paused");
localDB.allDocs().then(function(docs){
console.log("allDocs");
docs.rows.forEach(function(row){
console.log(row);
remoteDB.get(row.id)
.then(function(doc){
if(doc.Agents.indexOf(agent) < 0){
localDB.remove(doc);
}
});
});
});
})
.on('change', function(result){
console.log("change!");
result.change.docs.forEach(function(change) {
if(!change.deleted){
$rootScope.$apply(function(){
$rootScope.$broadcast('upsert', change);
});
}
});
});
Каждое удаление () дает мне 409 (конфликт), и это справедливо. Есть ли способ сказать Пучу "больше не считать это реплицируемым и просто удалить его из моей БД?"
3 ответа
(3) Мне кажется, самое простое решение, то есть решение "база данных на роль".
Я думаю, что ваша трудность связана с попыткой управлять разрешениями внутри самих документов (а затем с помощью фильтрации репликации). Когда вы делаете это, вы в основном пытаетесь отразить систему разрешений CouchDB внутри ваших документов, что может вызвать головную боль.
Почему бы не создать базу данных для каждой роли и назначить роли пользователям, используя обычные _users
база данных? Если роли изменятся, пользователи потеряют или получат доступ к набору документов. Вам потребуется иметь конечные точки сервера для обработки перетасовки ролей, или вам нужно будет настроить отдельные базы данных "admin" со специальными привилегиями, где пользователи могут менять роли.
Затем на стороне клиента вы можете либо выполнить репликацию из нескольких баз данных CouchDB в одну PouchDB (а затем сопоставить результаты самостоятельно), либо в одну PouchDB (вероятно, плохая идея, если вам необходимо синхронизировать данные в двух направлениях). Очевидно, вам понадобится начальный шаг, чтобы определить, к каким базам данных пользователь имеет доступ, но, на мой взгляд, это небольшой недостаток.
Затем, если пользователь потеряет доступ к документу, он просто получит обычные ошибки 401 во время репликации (которые будут отображаться в 'denied'
событие во время живой репликации). Нет необходимости в ddoc или отфильтрованной репликации - намного проще!
Мы пришли к выводу, что:
1) наш сценарий использования может не подходить для CouchDB
2) мы ценим наше психическое здоровье. После почти месяца борьбы с этой проблемой мы бы предпочли потерпеть неудачу
3) документы относительно недороги, поэтому даже если они остаются на телефоне пользователя, это не вызовет серьезных проблем. Если данные накапливаются слишком много, они могут просто очистить данные и начать заново
Решение:
1) Сохранить архитектуру, как указано в пункте 1
2) После каждого события 'паузы' сравнивайте локальные документы с удаленными документами, если удаленный документ не проходит фильтр, удалите его из пользовательского интерфейса. Если есть способ удалить только локальный документ, мы будем очень заинтересованы в обновлении этой логики.
1) до сих пор звучит как самый простой подход ко мне..
Я не очень хорошо знаю PouchDB, но в простом CouchDB изменения в удаленном документе можно обойти, расширив атрибуты удаленного документа, используя собственную функцию DELETE.
Я имею в виду... удаление похоже на обновление, которое устанавливает для атрибута _deleted значение true.
Таким образом, вместо непосредственного удаления документов, используя обычное CouchDB crud DELETE для документа, вы можете создать функцию обновления, например:
function(doc,req){
// optional acls for deleting doc.. doc is owned by req.userCtx.name
// doc.users are users already granted to work with this doc
return [{
"_id" : doc._id,
"_rev": doc._rev,
"_deleted":true,
"users": doc.users
},"Ok doc deleted"];
}
Кроме того, используя правила переписывания документов, эту функцию обновления можно в конечном итоге вызвать даже при отправке HTTP-запроса DELETE (не только на PUT или POST). Таким образом, ваше поведение удаления становится полностью прозрачным для клиента... и вы удаляете в способ, который может быть более полезным для вашего случая использования.
В учебном приложении Smileupps Chatty couchapp используется такой подход: расширенные операции удаления для различных типов документов выполняются в файлах user / drop.js, profile / drop.js, chat / drop.js.