【问题标题】:CouchDB replication strategy with dynamic groups of users具有动态用户组的 CouchDB 复制策略
【发布时间】:2015-05-06 14:24:12
【问题描述】:

情况是这样的:
我们有一系列共享一些文档的用户。他们可以共享的文档可能会在一天中发生变化,文档本身也会发生变化(更改和删除)。用户可以更改文档上的一些信息。
例如
用户 |文件
一个 | X
一个 |是的
一个 | Z
乙| X
乙| Z
C |是的

可能的组:A+C、A+B

CouchDB 上的服务器是具有此数据的 SQL Server DB 的副本,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);
                    });
                }
            });
    });

每个 remove() 都会给我一个 409(冲突),这是理所当然的。有没有办法告诉 Pouch“不再认为这是可复制的,只需将其从我的数据库中删除?”

【问题讨论】:

  • 您可能还想尝试在#couchdb IRC 会议室提出这个问题。他们在此类复杂的权限系统方面拥有更多经验。
  • 这是个好建议。下周我们还将见到一位离线优先应用程序的顾问。希望他能有一些见解。

标签: couchdb replication database-replication pouchdb recipe


【解决方案1】:

1) 对我来说仍然是最简单的方法..

我不太了解 PouchDB,但在普通 CouchDB 中,可以通过扩展已删除文档的属性来解决已删除文档的更改,使用您自己的自定义 DELETE 函数。

我的意思是.. 删除类似于将 _deleted 属性设置为 true 的更新。

因此,不是直接删除文档,而是使用普通的 CouchDB crud DELETE on document,您可以创建一个更新函数,如下所示:

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 tutorial app 使用这种方法:针对不同文档类型的扩展删除在 user/drop.jsprofile/drop.js, chat/drop.js 文件

【讨论】:

  • 这种方法适用于 PouchDB 和 CouchDB,是的。
  • 感谢@nlawson,我们实现了解决方案 1。“_changes 提要中不存在无法通过过滤器的文档更改(例如,从数组中删除用户)”的问题仍然存在然而。我已经和我的老板详细讨论过了,我们决定一些熵客户端是可以接受的。我们更改了文档的类型(构成文档的层次结构级别)以减少影响。这意味着“错误”文档最多只能被客户看到 30 天,然后在最坏的情况下被删除。
【解决方案2】:

我们得出的结论是:
1) 我们的用例可能不适合 CouchDB
2)我们重视我们的心理健康。经过近一个月的努力解决这个问题,我们宁愿尝试失败
3) 文件相对便宜,所以即使留在用户的手机上也不会造成太大的困扰。如果数据积累过多,他们可以简单地清除数据并重新开始

解决方案:
1) 保持架构与第 1 点一致
2) 在每个“暂停”事件触发后,将本地文档与远程文档进行比较,如果远程文档未通过过滤器,则将其从 UI 中删除。如果有办法只删除本地文档,我们将对升级到该逻辑非常感兴趣。

【讨论】:

    【解决方案3】:

    (3) 对我来说似乎是最简单的解决方案,即“每个角色的数据库”解决方案。

    我认为您的困难源于尝试管理文档本身内部的权限(然后使用过滤复制)。当您这样做时,您基本上是在尝试将 CouchDB 的权限系统镜像到您的文档中,这会让人头疼。

    为什么不为每个角色创建一个数据库,并使用普通的_users 数据库为用户分配角色?如果角色发生变化,那么用户将失去或获得对一组文档的访问权限。您需要有服务器端点来处理角色改组,或者您需要设置具有特殊权限的单独“管理员”数据库,用户可以在其中更改角色。

    然后在客户端,您可以从多个 CouchDB 数据库复制到单个 PouchDB(然后自己将结果整理在一起),或者复制到单个 PouchDB(如果您需要双向同步,这可能是个坏主意)。显然,您需要一个初始步骤来确定用户可以访问哪些数据库,但我认为这是一个小的缺点。

    然后,如果用户失去对文档的访问权限,他们将在复制期间简单地得到正常的 401 错误(这将在实时复制期间显示在 'denied' 事件中)。无需 ddocs 或过滤复制 - 更简单!

    【讨论】:

    • 你最后一段很有趣,我不知道,确实很有用。过滤复制不会触发此行为吗? (不再在过滤器中的文档显示在被拒绝的事件中)。我认为最大的问题是“角色”(所以数据库)在每天开始时都会改变他们的容器(他们的文档)。基本上数据库和角色每天都会更新,我们不能让用户每天下载数百 MB。用领域术语来说:我们有不同路线的推销员,一些节点对于多个推销员来说是相同的。
    • 不,过滤复制不会告诉您文档何时不再在过滤器中。 TBH 听起来 Couch/Pouch 可能不适合您的领域。看起来您真正需要的只是带有一些轻型缓存的 AJAX,尤其是当销售人员的路线在很大程度上是只读的时。每天只下载一次他们的路线,然后把昨天的下载量一扫而光,对吧?
    • 我希望...销售人员的连接有数据上限,而 wifi 很粗略。客户端对下载大小非常敏感。无论如何,该应用程序需要离线工作。也许我只是想在同一个文档中放入太多信息。也许有两个数据库(路由、节点)并进行伪连接?我知道这在 noSQL 世界中是一种罪过,但是嘿...
    • 我已经更新了我的问题。 TL;DR:有没有办法告诉 Pouch“不再认为该文档是可复制的,而只是将其从我的数据库中删除?”
    • 那将是 purge() 函数,尚未实现。 github.com/pouchdb/pouchdb/issues/802 同时,您可以使用过滤复制从一个本地数据库复制到另一个本地数据库,然后销毁()旧数据库。或者直接忽略文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    相关资源
    最近更新 更多