【问题标题】:couchdb update design doccouchdb 更新设计文档
【发布时间】:2016-07-14 22:16:33
【问题描述】:

我有一个 nodejs 应用程序,我使用 nano 和以下脚本连接到我的 couchdb:

const { connectionString } = require('../config');

const nano = require('nano')(connectionString);

// creates database or fails silent if exists
nano.db.create('foo');

module.exports = {
  foo: nano.db.use('foo')
}

此脚本在每次服务器启动时运行,因此它会在每次服务器(重新)启动时尝试创建数据库“foo”,如果数据库已经存在,则会静默失败。

我非常喜欢这个想法,因为这样我实际上是在应用程序级别维护数据库,并且在我决定添加新数据库时不必手动创建数据库。

进一步采用这种方法,我还尝试从应用程序级别维护我的设计文档。

... 
nano.db.create('foo');

const foo = nano.db.use('foo');

const design = {
  _id: "_design/foo",
  views: {
    by_name: {
      map: function(doc) {
        emit(doc.name, null);
      }
    }
  }
}

foo.insert(design, (err) => {
  if(err)
    console.log('design insert failed');
})

module.exports = {
  foo
}

显然,这只会在设计文档不存在时插入。但是,如果我更新了我的设计文档并想要更新它怎么办?

我试过了:

foo.get("_design/foo", (err, doc) => {
  if(err)
    return foo.insert(design);

  design._rev = doc._rev
  foo.insert(design);
})

现在的问题是设计文档会在每次服务器重新启动时更新(例如,每次重新启动时都会获得一个新的 _rev)。

现在...我的问题:)

1:这是用数据库和设计引导我的 CouchDB 的糟糕方法吗?我应该考虑将一些迁移步骤作为我的部署过程的一部分吗?

2:我的设计文档获得许多 _revs,基本上是每次部署和服务器重新启动时都会出现问题吗?即使文件本身没有改变?如果是这样,有没有办法只在文档更改时才更新文档? (我想在我的应用程序中手动将 _rev 设置为某个值,但我不确定这是否是个好主意)。

【问题讨论】:

    标签: database deployment couchdb seeding couchdb-nano


    【解决方案1】:
    1. 您的方法似乎很合理。如果仅在重新启动时进行检查,这甚至不会是性能问题。
    2. _revs 太多可能会成为问题。 _revs 的历史记录保存为_revs_info,并与文档本身一起存储(see the CouchDB docs for details)。根据您的设置,创建不必要的修订可能是一个错误的决定。

    对于一些需要特定视图的服务器端脚本,我们遇到了类似的挑战。我们的解决方案是计算新旧设计文档的哈希值并进行比较。您可以为此作业使用任何散列函数,例如sha1 或md5。 请记住在散列之前从旧文档中删除 _rev,否则您每次都会得到不同的散列值。

    【讨论】:

    • 谢谢伯恩哈德。你的解释真的很有帮助。我通过简单地比较设计文档来接受您的建议,但是在将它们与 md5 进行比较时遇到了一些麻烦......我根据您在下面的建议发布了自己的解决方案。能否请您提供反馈意见?
    【解决方案2】:

    我尝试了 @Bernhard Gschwantner 建议的 md5 比较。但是我遇到了一些困难,因为我想在我的代码中用纯 javascript 在设计文档中编写 map/reduce 函数。

    const design = {
      _id: "_design/foo",
      views: {
        by_name: {
          map: function(doc) {
            emit(doc.name, null);
          }
        }
      }
    }
    

    从 CouchDb 获取设计文档时,会返回转换为字符串的 map/reduce 函数:

      ...
      "by_name": {
        "map": "function (doc) {\n        emit(doc.name, null);\n      }"
      },
      ...
    

    显然 md5 比较在这里不起作用。

    我最终得到了一个非常简单的解决方案,只需在设计文档上添加一个版本号:

    const design = {
      _id: "_design/foo",
      version: 1,
      views: {
        by_name: {
          map: function(doc) {
            emit(doc.name, null);
          }
        }
      }
    }
    

    当我更新设计文档时,我只是增加版本号并将其与数据库中的版本号进行比较:

    const fooDesign = {...}
    foo.get('_design/foo', (err, design) => {
      if(err)
        return foo.insert(fooDesign);
    
      console.log('comparing foo design version', design.version, fooDesign.version);
      if(design.version !== fooDisign.version) {
        fooDesign._rev = design._rev;
        foo.insert(fooDesign, (err) => {
          if(err)
            return console.log('error updating foo design', err);
          console.log('foo design updated to version', fooDesign.version)
        });
      }
    });
    

    【讨论】:

    • 这也很棒而且更简单。但是,如果您想使用 md5 散列,您可以通过遍历对象属性并调用 prop.toString() 将函数转换为字符串,从而将 javascript 函数转换为字符串。但这需要更多工作,因此版本字段是更简单且更易于理解的解决方案。
    【解决方案3】:

    再次回顾您的问题:在最近的一个项目中,我使用了 Johannes Schmidt 的出色 couchdb-push 模块。您可以免费获得条件更新,以及从其依赖项 couchdb-compile 继承的 many other benefits。

    那个图书馆对我来说是一块隐藏的宝石。强烈推荐!

    【讨论】:

      猜你喜欢
      • 2019-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-14
      • 2012-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多