CouchDB 从设计文档中读取配置

CouchDB Read Configuration from design document

我想在配置文件中存储一个值,并在设计文档中查找它以与更新值进行比较。我确定我看过这个,但是,对于我的一生,我似乎不记得如何做到这一点。

更新

我意识到(在第一个答案之后)有不止一种方法可以解释我的问题。希望这个例子能澄清一点。给定一个配置:

curl -X PUT http://localhost:5984/_config/shared/token -d '"0123456789"'

然后我希望能够在我的设计文档中查找它

{
  "_id": "_design/loadsecrets",
  "validate_doc_update": {
    "test": function (newDoc,oldDoc) { 
       if (newDoc.supersecret != magicobject.config.shared.token){
         throw({unauthorized:"You don't know the super secret"});
       } 
    }
  }
}

这是我正在寻找的 magicobject.config.shared.token 的能力。

更新 2

另一个可能有用的(人为的)场景

curl -X PUT http://trustedemployee:5984/_config/eventlogger/detaillevel -d '"0"'
curl -X PUT http://employee:5984/_config/eventlogger/detaillevel -d '"2"'
curl -X PUT http://vicepresident:5984/_config/eventlogger/detaillevel -d '"10"'

然后在跟踪员工行为的设备上:

{
  "_id": "_design/logger",
  "updates": {
    "logger": function (doc,req) { 
      if (!doc) {
        doc = {_id:req.id};
      }
      if(req.level < magicobject.config.eventlogger.detaillevel ){
        doc.details = req.details;
      }
      return [doc, req.details];
    }
  }
}

认为我知道你在说什么,如果我是对的,那么你所要求的就不再可能了。 (至少在v1.6和v2.0中,我不确定这个功能是什么时候被移除的)

有一个鲜为人知的技巧允许 view/show/list/validation/etc 函数在您的函数中访问父设计文档作为 this。例如:

{
  "_id": "_design/hello-world",
  "config": {
    "PI": 3.14
  },
  "views": {
    "test": {
      "map": "function (doc) { emit(this.config.PI); })"
    }
  }
}

这是一个真正疯狂的想法,我想它被删除是因为它在设计文档和视图代码之间创建了循环依赖关系,从而使invalidating/rebuilding 视图索引是一件非常棘手的事情。

我记得在很久以前的某个时候使用过这个技巧,但这个功能现在肯定已经消失了。 (而且可能永远不会 return)

对于您的特殊用例(使用秘密令牌验证文档),可能 是一种解决方法,但我不确定令牌是否会在某些情况下泄漏地方。这完全取决于您的安全要求。

您可以滥用 validate_doc_update 的第 4 个参数,securityObject(参见 the CouchDB docs)将秘密令牌存储为第一个管理员名称:

{
  "test": "function (newDoc, oldDoc, userCtx, secObj) {
    var token = secObj.admins.names[0];
    if (newDoc.supersecret != token) {
      throw({unauthorized:"You don't know the super secret"});
    }
  }"
}

因此,如果将数据库的安全对象设置为 {admins: {names: ["s3cr3t-t0k3n"], roles: ["_admin"]}},则必须传递 's3cr3t-t0k3n' 作为文档的超级机密 属性。

这显然是一个肮脏的黑客攻击,但据我所知,安全对象只能由管理员读取或修改,你不会立即将你的令牌泄露给 public。但是,如果您需要 "real" 安全性,请考虑在 CouchDB 和您的调用者之间添加一个单独的层。

这是我上一个回答的后续内容,包含更一般的信息:

没有使用配置的通用方法,因为 CouchDB 在设计时考虑了可伸缩性、稳定性和可预测性。它的设计使用了 functional programming and pure functions 的许多原则,尽可能避免副作用。这是一件好事™。

但是,每种类型的函数都有您可以使用的附加参数,具体取决于调用函数的上下文:

  • show, list, update and filter函数是针对每个请求执行的,因此得到了请求对象。这里有 req.secObjreq.userCtx 用于(ab)通用配置。此外,AFAIK this 关键字设置为当前设计文档,因此您可以使用设计文档来获取通用配置(至少在 CouchDB 1.6 之前有效)。
  • view functions (map, reduce) don't have additional parameters, because the results of a view are written to disk and reused in subsequent calls. map functions must be pure (so don't use e.g. Math.random()). For shared configuration across view functions within a single design doc you can use CommonJS require(), but only within the views.lib key.
  • validate doc update 函数不一定在用户触发的 http 请求中执行(它们在每次写入之前调用,可能不会仅通过 http 触发)。所以他们在函数签名中添加了 userCtxsecObj 作为单独的参数。

所以综上所述,可以使用以下几个地方进行配置:

  • userCtx 用于用户特定的配置。使用特殊角色(例如带有前缀)来存储小的配置位。例如 superLogin 就是这样做的。
  • secObj 用于数据库范围的配置。为小位使用特殊的成员名称(因为您通常应该使用角色而不是明确的用户名,secObj.members.namessecObj.admins.names 是个好地方)。
  • 设计文档本身用于设计文档范围的配置。最好为此使用 this.views.lib.config,因为您也可以从视图中读取此键。但请记住,一旦更改此键,所有视图都会失效。因此,如果无论配置值是什么,视图结果都将保持不变,则最好使用 this.config 键。

希望这对您有所帮助!如果您愿意,我也可以添加示例。