更新文档时的 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 的设备。
这些是我执行的步骤:
- 我将两个数据库同步在一起。所以现在我的设备上有此文档的最新版本。
- 我 运行 下面的查询,我得到了所有三个模板,如下所示:
代码
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 }
我更新模板:云上人。然后我再次更新它。所以 2 次修订已经过去,但没有同步到我的设备。
我与我的设备同步。
- 现在当我 运行 相同的查询时,我只取回我编辑的文档。这很奇怪,因为我没有触及任何其他文件。相同的视图 return 是云上的预期结果,但不是设备上的结果。
return
{"11111": true}
- 但是,如果我执行以下代码,所有模板都会正常返回,并且来自云的相同
_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});
这样可以确保所有组件都是最新的。
假设我有这三个文件:
{ "_id": "11111", "type": "template", "name": "person" }
{ "_id": "22222", "type": "template", "name": "place" }
{ "_id": "33333", "type": "template", "name": "thing" }
我有一个云数据库,然后我有一个从该数据库同步 pouchDB 的设备。
这些是我执行的步骤:
- 我将两个数据库同步在一起。所以现在我的设备上有此文档的最新版本。
- 我 运行 下面的查询,我得到了所有三个模板,如下所示:
代码
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 }
我更新模板:云上人。然后我再次更新它。所以 2 次修订已经过去,但没有同步到我的设备。
我与我的设备同步。
- 现在当我 运行 相同的查询时,我只取回我编辑的文档。这很奇怪,因为我没有触及任何其他文件。相同的视图 return 是云上的预期结果,但不是设备上的结果。
return
{"11111": true}
- 但是,如果我执行以下代码,所有模板都会正常返回,并且来自云的相同
_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});
这样可以确保所有组件都是最新的。