Pouchdb PockDB和Couchbase中的多个唯一字段约束和最终冲突解决
当我有具有多个唯一字段约束的文档时,我无法找到适当的解决方案来处理“最终冲突”(有关“最终冲突”的描述,请参阅),与用户注册文档或具有唯一名称和标题的文章文档的唯一用户名约束和唯一电子邮件约束一样,所有文档都使用Ionic+PockDB和Couchbase Sync Gateway在移动设备上实时复制 让我们以具有唯一Pouchdb PockDB和Couchbase中的多个唯一字段约束和最终冲突解决,pouchdb,Pouchdb,当我有具有多个唯一字段约束的文档时,我无法找到适当的解决方案来处理“最终冲突”(有关“最终冲突”的描述,请参阅),与用户注册文档或具有唯一名称和标题的文章文档的唯一用户名约束和唯一电子邮件约束一样,所有文档都使用Ionic+PockDB和Couchbase Sync Gateway在移动设备上实时复制 让我们以具有唯一名称约束和唯一标题约束的文章文档为例 1) 。我有一篇文章文档,看起来像这样: { "_id": "article::3808cea0-bb99-11e5-9ba4-315d4
名称
约束和唯一标题
约束的文章
文档为例
1) 。我有一篇文章
文档,看起来像这样:
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user-id-here"
}
db.sync('remote db url', {
live: true,
retry: true
})
db.changes({
since: 'now',
live: true,
include_docs: true,
conflicts: true
}).on('change', function(change) {
if (change.doc._conflicts) {
// do coflict resolution
}
});
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-de7e0636632764e97880f362d50598b7",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "name",
"propertyValue": "name1"
}
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-34c1771f2108f6ad8efc0d99e79d78a0",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "title",
"propertyValue": "title1"
}
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user1"
}
2) 。此外,我正在为每个唯一字段创建单独的约束文档(请参见和),其中“\u id”键的格式为“{doc type}--constraint unique--{unique property/field name}::{sha256}”
因此,对于上面带有“name1”和“title1”的文档,我为name
字段和title
字段创建了两个“ConstraintUnique”文档/占位符
唯一的“名称”字段占位符文档:
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-de7e0636632764e97880f362d50598b7",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "name",
"propertyValue": "name1"
}
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-34c1771f2108f6ad8efc0d99e79d78a0",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "title",
"propertyValue": "title1"
}
唯一的“标题”字段占位符文档:
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-de7e0636632764e97880f362d50598b7",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "name",
"propertyValue": "name1"
}
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-34c1771f2108f6ad8efc0d99e79d78a0",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "title",
"propertyValue": "title1"
}
在所有“ConstraintUnique”文档上,我有“docRef”字段,该字段指向实际文档的“\u id”,如“文章。\u id”
3) 。这样,如果我想在将来添加更多独特的约束,我只需添加另一个“约束文档”,当我保存/创建新文章时,我会检查现有的“约束文档”,然后保存或拒绝原始文档。另一个选项是插入没有附加“约束文档”的文档,并使用视图检查是否存在副本,然后立即删除副本。(此处描述了所有内容:)
问题:
我正在执行实时双向复制(客户端到服务器和服务器到客户端同步),如下所示:
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user-id-here"
}
db.sync('remote db url', {
live: true,
retry: true
})
db.changes({
since: 'now',
live: true,
include_docs: true,
conflicts: true
}).on('change', function(change) {
if (change.doc._conflicts) {
// do coflict resolution
}
});
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-de7e0636632764e97880f362d50598b7",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "name",
"propertyValue": "name1"
}
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-34c1771f2108f6ad8efc0d99e79d78a0",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "title",
"propertyValue": "title1"
}
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user1"
}
然后,我倾听这样的变化:
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user-id-here"
}
db.sync('remote db url', {
live: true,
retry: true
})
db.changes({
since: 'now',
live: true,
include_docs: true,
conflicts: true
}).on('change', function(change) {
if (change.doc._conflicts) {
// do coflict resolution
}
});
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-de7e0636632764e97880f362d50598b7",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "name",
"propertyValue": "name1"
}
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-34c1771f2108f6ad8efc0d99e79d78a0",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "title",
"propertyValue": "title1"
}
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user1"
}
我有以下场景,其中两个用户都处于脱机状态,没有数据同步到远程数据库,但数据插入到他们的本地数据库中:
1) User1
处于脱机状态,他用name1
和title1
插入了Article
,他的本地数据库将如下所示:
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user-id-here"
}
db.sync('remote db url', {
live: true,
retry: true
})
db.changes({
since: 'now',
live: true,
include_docs: true,
conflicts: true
}).on('change', function(change) {
if (change.doc._conflicts) {
// do coflict resolution
}
});
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-de7e0636632764e97880f362d50598b7",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "name",
"propertyValue": "name1"
}
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-34c1771f2108f6ad8efc0d99e79d78a0",
"type": "ConstraintUnique",
"docRef": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"propertyName": "title",
"propertyValue": "title1"
}
{
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user1"
}
2) User2
也处于脱机状态,他正在插入带有name1
和title1
的相同文章,因此他的本地数据库看起来几乎相同,但带有不同的文章。_id
和相同的ConstraintUnique
id:
Same as User1's (except _rev and docRef):
{
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"_rev": "1-5c427cba5efe71114acb7e6ddd8b8a23",
"type": "ConstraintUnique",
"docRef": "article::ad16f2e4-9cff-42ae-ae92-27e353e7f229",
"propertyName": "name",
"propertyValue": "name1"
}
Same as User1's (except _rev and docRef):
{
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7",
"_rev": "1-14244246dbbac7e55e132abe47fe115d",
"type": "ConstraintUnique",
"docRef": "article::ad16f2e4-9cff-42ae-ae92-27e353e7f229",
"propertyName": "title",
"propertyValue": "title1"
}
Different, but the actual data is the same:
{
"_id": "article::ad16f2e4-9cff-42ae-ae92-27e353e7f229",
"_rev": "1-8b8076d3fef9994ca65a516532c5f975"
"type": "Article",
"name": "name1",
"title": "title1",
"owner": "user2"
}
3) 。实际问题是:
当User 1
重新联机并且其更改与远程数据库同步时,不会发生冲突:
Ids of the docs:
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7"
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9"
Ids of the docs:
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" -- conflicting with the User1
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7" -- conflicting with the User1
"_id": "article::ad16f2e4-9cff-42ae-ae92-27e353e7f229" -- no conflict, but I need to remove this duplicate somehow
稍后,User 2
也重新联机,他的更改与远程数据库同步,但存在冲突:
Ids of the docs:
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7"
"_id": "article::3808cea0-bb99-11e5-9ba4-315d40280ab9"
Ids of the docs:
"_id": "article--constraint-unique--name::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" -- conflicting with the User1
"_id": "article--constraint-unique--title::5018e26faaec56a465e61aaeb752c2984c8a6d6305c8496b3a95213fb20889c7" -- conflicting with the User1
"_id": "article::ad16f2e4-9cff-42ae-ae92-27e353e7f229" -- no conflict, but I need to remove this duplicate somehow
因此,CouchDB/Couchbase同步网关在服务器端为“文章——约束唯一性——名称::E3B0C44298FC1C149AFBF4C8996FB92427AE41E46499B934CA495991B7852B855”和“文章——约束唯一性——标题::5018E26FAAEC56A465E61AEB752C29C8A6305C8496B3A95213B0889C7”选择赢家,但是客户端上的PockDB也同步重复的文章文档-我想清理约束文档冲突(“文章--约束唯一--名称::e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855”和“文章--约束唯一--标题::5018E26FAAEC56A465E61AAEB752C2984C8A6305C8496B3A95213B20889C7”)并更新docRef(如果docRef在“名称”和“标题”约束上不相同,我还想删除ID为的重复文章。”article::3808cea0-bb99-11e5-9ba4-315d40280ab9“(用户1)和“article::ad16f2e4-9cff-42ae-ae92-27e353e7f229”(用户2)或更好我想选择一篇获奖文章,然后更新“文章中的docRef——约束唯一性“文件。任何解决方案都是受欢迎的-我只想删除重复的文章并更新约束占位符以与获奖文章同步
我已经完成了原始实现,在那里我检查了变更提要()中的冲突,我正在使用Ionic 1/AngularJS 1+PockDB并尝试删除重复的文档/文章:
var changeListener = db.changes({
since: 'now',
live: true,
include_docs: true,
conflicts: true
}).on('change', function(change) {
var doc = angular.copy(change.doc);
var i;
if (doc._conflicts) {
if (doc.type && (doc.type === 'ConstraintUnique')) {
for (i = 0; i < doc._conflicts.length; i++) {
(function(currentConflictRev) {
// get conflicted "ConstraintUnique"
db.get(doc._id, {rev: currentConflictRev}).then(function(conflictConstraintUniqueDoc) {
if (conflictConstraintUniqueDoc.docRef) {
// get linked to "ConstraintUnique" doc and delete it
db.get(conflictConstraintUniqueDoc.docRef)
.then(function(conflictDoc) {
// delete the duplicated doc
db.remove(conflictDoc._id, conflictDoc._rev);
// resolve the current conflict
db.remove(conflictConstraintUniqueDoc._id, conflictConstraintUniqueDoc._rev);
});
}
});
})(doc._conflicts[i]);
}
}
}
});
var changelister=db.changes({
因为:"现在",,
现场直播:没错,
包含文档:true,
冲突:对
}).on('change',函数(change){
var doc=角度复制(change.doc);
var i;
如果(单据冲突){
如果(doc.type&&(doc.type==='ConstraintUnique')){
对于(i=0;i
当coach服务器决定赢得“constraintonique”的name文档与docRef==user1Article和另一个获胜的“constraintonique时,此实现不起作用title的文档带有docRef==user2Article——这样就删除了两篇文章,而不仅仅是重复的一篇