简体   繁体   中英

pouchDB query() bug when updating documents

Let's say I have these three documents:

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

I have a cloud database and then I have a device with pouchDB syncing from that database.

These are the steps that I do:

  1. I sync both databases together. So now I have the most recent versions of this document on my device.
  2. I run the below query and I get back all three templates like so:

Code

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. I update template: person on cloud. And then I update it again. So 2 revisions have gone by without syncing to my device.

  2. I sync with my device.

  3. Now when I run the same query and I only get back the document I edited. Which is weird because I haven't touched any of the other documents. The same view returns the expected results on the cloud but not on the device.

return

{"11111": true}
  1. If I do the following code however, all templates come back as normal and the same _rev from the cloud show up on the device. Meaning the sync was successful and view is getting confused.

new code

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

I'm starting to believe this is a bug because if I destroy my database and do these steps again, I can reproduce this issue.

After realizing you are using React Native, I think this actually has to do with PouchDB in React Native, and it's indeed a bug. There are several reports of that behavior:

[edit: Seems to be a bug in PouchDB with React Native. I leave this answer because it might be helpful in other ways.]

I suspect it's some side effect with the global variable template_obj you are using. Try to console.log(templates.rows) directly instead of storing it in a variable in the top scope, or use Array.reduce() to avoid side effects. Then you'd always get the correct view results.

This is step by step code:

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.

Or more concise with ES2015+:

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

By the way: You could also use other strategies to "filter" your documents, as it's not necessary to emit the _id. Instead you can use the key and/or value for "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); }
  }
}
  • you can use docs/byType as an universal view for other doc types too. Just call it with db.query('docs/byType', { key: 'template' })
  • If you want the templates sorted by name, use db.query('docs/templatesByName') or db.query('docs/byTypeAndName', { startkey: ['template'], endkey: ['template', {}]}) .

A word of caution: This is all untested and just from memory, so some brackets might be missing in the code, or some bugs might hide in there.

It's not a bug in PDB, it's about outdated unfortunately components in pouchdb-react-native. Confirmed way is to combine pouchdb-react-native yourself like this - then queries work as expected:

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

This way one can be sure that all components are the latest.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM