代码之家  ›  专栏  ›  技术社区  ›  Tobias Mesquita

将数据从PouchDb复制到CouchDb时失败

  •  3
  • Tobias Mesquita  · 技术社区  · 6 年前

    我的代码

    这是我当前代码的简短版本:

    ['tableA', 'tableB', 'tableC'].forEach(name => {
        let local = new PouchDB(name, { auto_compaction: true })
        let server = new PouchDB(serverUrl + name)
    
        var filtro = {
          include_docs: true,
          filter: 'replication/by_dispositivo',
          query_params: { 'dispositivo_id': obj.deviceId }
        }
        local.replicate.from(server, filtro).on('complete', report => {
          var sync = local.sync(server, {
            live: true,
            retry: true,
            ...filtro
          })
        })
    })
    

    我正在尝试进行实时复制,但由于某种原因,它无法将本地数据复制到服务器,奇怪的是, PouchDb 未引发任何异常。

    检查 Network 选项卡打开 Dev Tools ,我可以看到te跟踪请求:

    URL: ${serverUrl}/{name}/_revs_diff
    Response: {
        "4b0ea507-cd88-4998-baf0-01629b50516b": {
            "missing": [
                "2-2133d30de8d44ebd958cee2b68726ffb"
            ],
            "possible_ancestors": [
                "1-39904a7e55b1cb266c840a2acf34fdc2"
            ]
        }
    }
    

    好的,PockDB检测到服务器中缺少某些内容,必须进行复制。

    审核同步

    为了寻找关于发生了什么的提示,我修改了代码以记录 complete error 事件:

    ['tableA', 'tableB', 'tableC'].forEach(name => {
        let local = new PouchDB(name, { auto_compaction: true })
        let server = new PouchDB(serverUrl + name)
    
        let filtro = {
          include_docs: true,
          filter: 'replication/by_dispositivo',
          query_params: { 'dispositivo_id': obj.deviceId }
        }
        local.replicate.from(server, filtro).on('complete', report => {
          let sync = local.sync(server, {
            live: true,
            retry: true,
            ...filtro
          })
          sync.on('error', (error) => {
            console.error(error)
            console.error(JSON.stringify(error, null, 2))
          }).on('complete', (result) => {
            console.log(result)
            console.log(JSON.stringify(result, null, 2))
          })
          window.setTimeout(function (evt) {
            state.syncProcess[database].cancel()
          }, 15000)
        })
    })
    

    我没有 catch 中的任何内容 错误 事件,以及 完成 事件未显示任何错误,如下文所示。

    {
      "push": {
        "ok": true,
        "start_time": "2018-04-06T15:00:42.266Z",
        "docs_read": 0,
        "docs_written": 0,
        "doc_write_failures": 0,
        "errors": [],
        "status": "cancelled",
        "end_time": "2018-04-06T15:00:42.266Z",
        "last_seq": 0
      },
      "pull": {
        "ok": true,
        "start_time": "2018-04-06T15:00:26.422Z",
        "docs_read": 0,
        "docs_written": 0,
        "doc_write_failures": 0,
        "errors": [],
        "last_seq": "17-g1AAAAJDeJyd0EsOgjAQBuAqJj52nkCPILGldCU3UaYzBA3CQl3rTfQmehO9CRZKAiaGiJtpMs18mX8SxtgodpBNdXbSMUKQZDpM4uxwTMxXP2Qwy_N8Fzsh25vGMILIA62QjU8pUrRNCVvGYW4qrCphUgoCfMVd_W2mTQoKaV1JjpWWIUcuu0qbQjp_pBKeUESLH1OlA1PZxTwGudb7EC1dQt5xH6vdrHYvtF6pSZK-4Oov7WG1Z53QUy56UnRK-LJK406-TxIAm8ruDdzts44",
        "status": "cancelled",
        "end_time": "2018-04-06T15:00:41.427Z"
      }
    }
    

    手动调用一次性本地到服务器复制

    这是我第二次尝试捕捉有用的东西。我正在努力 audit 这个 local.replicate.to method

    ['tableA', 'tableB', 'tableC'].forEach(name => {
        let local = new PouchDB(name, { auto_compaction: true })
        let server = new PouchDB(serverUrl + name)
    
        let filtro = {
          include_docs: true,
          filter: 'replication/by_dispositivo',
          query_params: { 'dispositivo_id': obj.deviceId }
        }
        local.replicate.from(server, filtro).on('complete', report => {
          local.replicate.to(server, filtro).on('complete', report => {
            console.log(report)
            console.log(JSON.stringify(report, null, 2))
            let sync = local.sync(server, {
              live: true,
              retry: true,
              ...filtro
            })
          }).on('error', (error) => {
            console.error(error)
            console.error(JSON.stringify(error, null, 2))
          })
        })
    })
    

    是时候了 完成 event 没有被解雇,我就抓到了 错误 ,但这太普通了,amd没有给出任何关于正在发生什么的线索。

    {
      "result": {
        "ok": false,
        "start_time": "2018-04-06T15:07:19.105Z",
        "docs_read": 1,
        "docs_written": 0,
        "doc_write_failures": 0,
        "errors": [],
        "status": "aborting",
        "end_time": "2018-04-06T15:07:19.768Z",
        "last_seq": 3
      }
    }
    

    将本地数据放入服务器

    这是我最后一次尝试

    • 我将查询本地和远程数据库(在这种情况下,我只有一个文档)
    • 将字段从本地文档复制到远程文档。
    • 将更新的远程文档发送到远程数据库

    我的垃圾邮件代码

    var deviceId = ''
    var listLocal = []
    var listServer = []
    
    getDeviceId().then(response => {
        deviceId = response
        return local.find({ selector: { dispositivo_id: deviceId } })
    }).then(response => {
        listLocal = response.docs
        return server.find({ selector: { dispositivo_id: deviceId } })
    }).then(response => {
        listServer = response.docs
    
        var tlocal = listLocal[0]
        var tServer = listServer[0]
        Object.keys(tServer).forEach(key => {
          if (key.indexOf("_") !== 0) {
            tServer[key] = undefined
          }
        })
        Object.keys(tlocal).forEach(key => {
          if (key.indexOf("_") !== 0) {
            tServer[key] = tlocal[key]
          }
        })
    
        return server.put(tServer).then(result => {
          console.log(result)
          console.log(JSON.stringify(result, null, 2))
        }).catch(error => {
          console.error(error)
          console.error(JSON.stringify(error, null, 2))
        })
    })
    

    垃圾代码按预期工作,我收到了响应:

    {
      "ok": true,
      "id": "4b0ea507-cd88-4998-baf0-01629b50516b",
      "rev": "2-d9363f28e53fdc145610f5ad3f75a043"
    }
    

    其他信息

    CouchDb中的我的设计文档

    _设计/复制

    {
      "_id": "_design/replication",
      "_rev": "1-42df919aaee8ed3fb309bbda999ba03d",
      "language": "javascript",
      "filters": {
        "by_dispositivo": "function(doc, req) {\r\n  return doc._id === '_design/replication' || (doc.dispositivo_id === req.query.dispositivo_id && !doc._deleted)\r\n}",
        "by_situacao_remote": "function(doc, req) {\r\n  return [2, 3, 4, 5].indexOf(doc.situacao) !== -1 && !doc._deleted\r\n}"
      }
    }
    

    _设计/授权

    {
      "_id": "_design/authorization",
      "_rev": "9-64c4a22645d783c9089c95d69e9424ad",
      "language": "javascript",
      "validate_doc_update": "..."
    }
    

    授权/验证\u doc\u更新

    function(newDoc, oldDoc, userCtx) {
      var isAdmin = userCtx.roles.indexOf('_admin') !== -1 || userCtx.roles.indexOf('admin') !== -1;
      if (!isAdmin) {
        if (newDoc._deleted) {
          if (oldDoc.dispositivo_id !== userCtx.name) {
            throw({forbidden: "..." });
          }
        } 
        else {
          if (!newDoc.dispositivo_id || !newDoc.dispositivo_id.trim())
            throw({forbidden: "..." });
          if (newDoc.dispositivo_id !== userCtx.name) {
            throw({forbidden: "..." });
          }
    
          if (oldDoc && oldDoc.dispositivo_id !== userCtx.name) {
            throw({forbidden: "..." });
          }
    
          var isRequired = function (prop, msg) {
            var value = newDoc[prop];
            if (!value)
                throw({forbidden: '...' });
          }
    
          var isDate = function (prop, msg, allow_null) {
            if (!allow_null) 
                isRequired(prop, msg)
            var value = newDoc[prop];
            if (value) {
                var date = new Date(value);
                var isDate = date !== "Invalid Date" && !isNaN(date);
                if (!isDate) {
                  throw({forbidden: msg });
                }
            }
          }
    
          var isFloat = function (prop, msg, allow_null) {
            if (!allow_null) 
                isRequired(prop, msg)
            var value = newDoc[prop];
            if (value) {
                var numero = new Number(value);
                if (!numero || isNaN(numero) || !isFinite(numero)) {
                  throw({forbidden: msg });
                }
            }
          }
    
          var isInteger = function (prop, msg, allow_null) {
            isFloat(prop, msg, allow_null)
            var value = newDoc[prop];
            if (value) {
                var numero = new Number(value);
                var isInteger = Math.floor(numero) == numero;
                if (!isInteger) {
                  throw({forbidden: msg });
                }
            }
          }
    
          isRequired("talao_id", "...");
          isRequired("equipe_id", "...");
    
          isInteger("situacao", '...');
          isDate("data_envio", "...");
          isDate("data_recebimento", "...", true);
          isDate("data_decisao", "...", true);
    
          isRequired("tipo_ocorrencia_codigo", "...");
          isRequired("tipo_ocorrencia_descricao", "...");
          isInteger("talao_codigo", "...");
          isRequired("talao_descricao", "...");
          isRequired("talao_solicitante", "...");
          isRequired("talao_endereco", "...");
        }
      }
      else if (!newDoc._deleted) {
        if (!newDoc.dispositivo_id || !newDoc.dispositivo_id.trim())
          throw({forbidden: "..." });
      }
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Tobias Mesquita    6 年前

    在分析 stack trace exception 抛开 local.replicate.to ,我注意到 reason: promise.all is not a function

    所以我在google上搜索了一会儿,找到了那个主题 Webpack: Promise is not a constructor .我只需要复制 workaround 向我的 webpack.config 一切都很有魅力

    resolve: {
      alias: {
        'pouchdb-promise$': "pouchdb-promise/lib/index.js"
      }
    }