具有动态用户组的CouchDB复制策略

时间:2015-03-05 09:19:43

标签: couchdb replication database-replication pouchdb recipe

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

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

CouchDB上的服务器是带有此数据的SQL Server数据库的副本,ETL负责管理CouchDB上的更改。但是,CouchDB数据库通过PouchDB在每个用户手机上复制。

目标:
相应地复制更改和删除。

我们尝试了什么:
1)我们认为我们使用可以访问它的用户列表来构建我们的文档。每个文档都有一个"用户"数组,然后设计文档中的过滤器将负责复制到客户端。遗憾的是,_changes Feed中不存在未通过过滤器的文档删除和文档更改(例如,用户已从阵列中删除),因此无法在客户端上进行相应的复制。 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&#34;不再认为这是可复制的,只是从我的数据库中删除它?&#34;

3 个答案:

答案 0 :(得分:2)

(3)对我来说似乎是最简单的解决方案,即每个角色的数据库&#34;溶液

我认为您的困难源于尝试管理文档内部的权限(然后使用过滤复制)。当你这样做时,你基本上是在试图在文档中反映CouchDB的权限系统,这会引起令人头疼的问题。

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

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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上),最终也可以调用此更新函数。这样,​​删除行为对客户端变得完全透明< / strong> ...并且您以对您的用例更有用的方式删除。

Smileupps Chatty couchapp tutorial app使用此方法:在 user / drop.js profile / drop中执行不同文档类型的扩展删除。 js chat / drop.js 文件