【问题标题】:pouchDB query() bug when updating documents更新文档时的 pouchDB 查询()错误
【发布时间】:2018-07-15 14:53:55
【问题描述】:

假设我有这三个文件:

{ "_id": "11111", "type": "template", "name": "person" }
{ "_id": "22222", "type": "template", "name": "place" }
{ "_id": "33333", "type": "template", "name": "thing" }

我有一个云数据库,然后我有一个带有从该数据库同步的 pouchDB 的设备。

这些是我要做的步骤:

  1. 我将两个数据库同步在一起。所以现在我的设备上已经有了这份文档的最新版本。
  2. 我运行以下查询,然后我得到了所有三个模板,如下所示:

代码

var template_obj = {};

return device_db.query('filters/templates')
.then((templates) => {
    for (let t of templates.rows) templates_obj[t.id] = true;
    return templates_obj;
});

过滤器/模板

function (doc) {
  if(doc.type == "template")
    emit(doc._id);
}

返回

{ "11111": true, "22222": true, "33333": true }
  1. 我更新模板:云上的人。然后我再次更新它。所以 2 次修订没有同步到我的设备。

  2. 我与我的设备同步。

  3. 现在,当我运行相同的查询时,我只取回我编辑的文档。这很奇怪,因为我没有触及任何其他文件。相同的视图会在云端返回预期结果,但不会在设备上返回。

返回

{"11111": true}
  1. 但是,如果我执行以下代码,所有模板都会正常返回,并且来自云端的相同 _rev 会显示在设备上。表示同步成功,视图变得混乱。

新代码

return device_db.allDocs({conflicts: true})
.then((data) => {
    for (let d of data.rows) {
        if(d.doc.type == "template") {
            templates_obj[d.doc._id] = true;
        }
    }
    return templates_obj;
 }).catch((err) => {
    console.log(JSON.stringify(err));
})

我开始相信这是一个错误,因为如果我销毁我的数据库并再次执行这些步骤,我可以重现此问题。

【问题讨论】:

  • 请添加您用于更新文档的代码?
  • @TarunLalwani 没有代码。我直接从 Cloudant 仪表板更新它们。
  • 你在对象上设置_rev
  • @TarunLalwani 如果您指的是我更新文档时,您必须包含 _rev。如果您要编辑文档,这与Fauxton 的工作方式相同。问题不在于我如何更新文档,因为过滤器在仪表板上工作。
  • 试图理解:您的代码实际上将返回单个对象,而不是对象数组。正确的?关键是 ID,而不是名称。所以正确的返回值是{'11111': true, '22222': true, '33333': true}

标签: javascript react-native couchdb pouchdb cloudant


【解决方案1】:

在意识到你使用的是 React Native 之后,我认为这实际上与 React Native 中的 PouchDB 有关,并且确实是一个错误。有几个关于这种行为的报告:

【讨论】:

  • 是的,其中一个实际上是我的报告。好像他们今天才承认。感谢您调查伯恩哈德
【解决方案2】:

[编辑:似乎是带有 React Native 的 PouchDB 中的一个错误。我留下这个答案是因为它可能在其他方面有帮助。]

我怀疑您正在使用的全局变量template_obj 有一些副作用。尝试直接console.log(templates.rows),而不是将其存储在顶级范围内的变量中,或者使用Array.reduce() 以避免副作用。然后你总是会得到正确的视图结果。

这是一步一步的代码:

return device_db.query('filters/templates')
  .then(templates => templates.rows)            // Take only the rows into account.
  .then(rows => rows.map(row => row.id)         // Extract the id. If you wanted the name instead this would be possible with a slightly different view.
                                                // I think it would suffice to log the result right now, 
                                                // but if you really want to have a single object with boolean values, 
                                                // you can do the following:
  .then(ids => ids.reduce((asObject, id) => {   // Use Array.reduce() here to avoid any potential side effects.
    asObject[id] = true;
    return asObject;
  }, {})
  .then(asObject => { console.log(asObject); }; // Debug the result.

或者使用 ES2015+ 更简洁:

return device_db.query('filters/templates')
  .then(({rows}) => rows.reduce((acc, {id}) => ({...acc, [id]: true }), {}))
  .then(result => console.log(result))

顺便说一句:您还可以使用其他策略来“过滤”您的文档,因为不需要发出 _id。相反,您可以使用“二级索引”的键和/或值:

{
  "_id": "_design/docs",
  "views": {
    "byType": "function(doc) { emit(doc.type); }",
    "templatesByName": "function(doc) { if (doc.type === 'template') emit(doc.name); }",
    "byTypeAndName": "function(doc) { emit([doc.type, doc.name], doc.name); }
  }
}
  • 您也可以使用 docs/byType 作为其他文档类型的通用视图。只需使用db.query('docs/byType', { key: 'template' }) 调用它
  • 如果您希望模板按名称排序,请使用db.query('docs/templatesByName')db.query('docs/byTypeAndName', { startkey: ['template'], endkey: ['template', {}]})

请注意:这一切都未经测试,仅凭记忆,因此代码中可能缺少一些括号,或者其中可能隐藏了一些错误。

【讨论】:

  • 我还用三个文档测试了你的视图函数,它应该总是返回这个:{"total_rows":3,"offset":0,"rows":[ {"id":"11111","key":"11111","value":null}, {"id":"22222","key":"22222","value":null}, {"id":"33333","key":"33333","value":null} ]}
  • 我刚刚意识到您正在使用 React Native(仅在标签中很难看到)。不过,您可以使用 console.log() 在安装了 React Native Debugger 的情况下进行调试。我仍然很确定您得到不正确结果的主要原因不是源于同步代码或冲突,也不是源于 map/reduce 视图。尽量简化和删除尽可能多的部分。
  • 感谢您的回复,但就像我在问题中所说的那样 - 它一直有效,直到它不起作用。它不像它从来没有工作过。当我将文档更新为比本地数据库已有的更深的两个修订版时,它停止工作。我试过做console.log(templates) 只是为了分析发现了什么。它与我最初的结果保持一致。这感觉更像是邮袋中的错误,而不是我的代码中的错误
【解决方案3】:

这不是 PDB 中的错误,不幸的是 pouchdb-react-native 中的组件已过时。 确认的方法是像这样自己组合 pouchdb-react-native - 然后查询按预期工作:

import PouchDB from 'pouchdb-core';
PouchDB
.plugin(require('pouchdb-adapter-asyncstorage').default)
.plugin(require('pouchdb-adapter-http'))
.plugin(require('pouchdb-mapreduce'))
.plugin(require('pouchdb-replication'))
.plugin(require('pouchdb-authentication'));
const localDB = new PouchDB(localDBname, {adapter: 'asyncstorage', auto_compaction: true});

这样可以确保所有组件都是最新的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 2016-10-06
    • 2018-01-20
    • 1970-01-01
    相关资源
    最近更新 更多