更新文档时的 pouchDB query() 错误

pouchDB query() bug when updating documents

假设我有这三个文件:

{ "_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;
});

filters/templates

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

return

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

  2. 我与我的设备同步。

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

return

{"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));
})

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

[编辑:似乎是带有 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))

顺便说一句:您还可以使用其他策略 "filter" 您的文档,因为没有必要发出 _id。相反,您可以使用键 and/or 值 "secondary indexes":

{
  "_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', {}]})

提醒一句:这一切都未经测试,仅来自记忆,因此代码中可能缺少一些括号,或者某些错误可能隐藏在其中。

发现你用的是React Native,我觉得这其实和React Native中的PouchDB有关,确实是个bug。有几份关于该行为的报告:

这不是 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});

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