从 CouchDB 中的 Erlang 视图发出元组

发布于 2024-08-24 17:26:39 字数 2447 浏览 5 评论 0原文

CouchDB,版本 0.10.0,使用本机 erlang 视图。

我有一个以下形式的简单文档:

{
   "_id": "user-1",
   "_rev": "1-9ccf63b66b62d15d75daa211c5a7fb0d",
   "type": "user",
   "identifiers": [
       "ABC",
       "DEF",
       "123"
   ],
   "username": "monkey",
   "name": "Monkey Man"
}

和一个基本的 javascript 设计文档:

{
   "_id": "_design/user",
   "_rev": "1-94bd8a0dbce5e2efd699d17acea1db0b",
   "language": "javascript",
   "views": {
     "find_by_identifier": {
       "map": "function(doc) {
          if (doc.type == 'user') {
            doc.identifiers.forEach(function(identifier) {
              emit(identifier, {\"username\":doc.username,\"name\":doc.name});
            });
          }
       }"
     }
   }
}

发出:

{"total_rows":3,"offset":0,"rows":[
{"id":"user-1","key":"ABC","value":{"username":"monkey","name":"Monkey Man"}},
{"id":"user-1","key":"DEF","value":{"username":"monkey","name":"Monkey Man"}},
{"id":"user-1","key":"123","value":{"username":"monkey","name":"Monkey Man"}}
]}

我正在考虑构建一个执行相同操作的 Erlang 视图。迄今为止最好的尝试是:

%% Map Function
fun({Doc}) ->
    case proplists:get_value(<<"type">>, Doc) of
    undefined ->
        ok;
    Type ->
        Identifiers = proplists:get_value(<<"identifiers">>, Doc),
        ID = proplists:get_value(<<"_id">>, Doc),
        Username = proplists:get_value(<<"username">>, Doc),
        Name = proplists:get_value(<<"name">>, Doc),
        lists:foreach(fun(Identifier) -> Emit(Identifier, [ID, Username, Name]) end, Identifiers);
    _ ->
        ok
    end
end.

发出:

{"total_rows":3,"offset":0,"rows":[
{"id":"user-1","key":"ABC","value":["monkey","Monkey Man"]},
{"id":"user-1","key":"DEF","value":["monkey","Monkey Man"]},
{"id":"user-1","key":"123","value":["monkey","Monkey Man"]}
]}

问题是 - 如何将这些值作为元组而不是数组获取?我不认为我可以(或不想)使用记录,但在元组中使用原子似乎不起作用。

lists:foreach(fun(Identifier) -> Emit(Identifier, {id, ID, username, Username, name, Name}) end, Identifiers);

失败并出现以下错误:

{"error":"json_encode","reason":"{bad_term,{<<\"user-1\">>,<<\"monkey\">>,<<\"Monkey Man\">>}}"}

想法?我知道 Erlang 对于这种特定的事情(命名访问)很糟糕,并且我可以按照约定来做到这一点(第一个位置是 id,接下来是用户名,最后是真实姓名),但这使得客户端代码非常丑陋。

CouchDB, version 0.10.0, using native erlang views.

I have a simple document of the form:

{
   "_id": "user-1",
   "_rev": "1-9ccf63b66b62d15d75daa211c5a7fb0d",
   "type": "user",
   "identifiers": [
       "ABC",
       "DEF",
       "123"
   ],
   "username": "monkey",
   "name": "Monkey Man"
}

And a basic javascript design document:

{
   "_id": "_design/user",
   "_rev": "1-94bd8a0dbce5e2efd699d17acea1db0b",
   "language": "javascript",
   "views": {
     "find_by_identifier": {
       "map": "function(doc) {
          if (doc.type == 'user') {
            doc.identifiers.forEach(function(identifier) {
              emit(identifier, {\"username\":doc.username,\"name\":doc.name});
            });
          }
       }"
     }
   }
}

which emits:

{"total_rows":3,"offset":0,"rows":[
{"id":"user-1","key":"ABC","value":{"username":"monkey","name":"Monkey Man"}},
{"id":"user-1","key":"DEF","value":{"username":"monkey","name":"Monkey Man"}},
{"id":"user-1","key":"123","value":{"username":"monkey","name":"Monkey Man"}}
]}

I'm looking into building an Erlang view that does the same thing. Best attempt so far is:

%% Map Function
fun({Doc}) ->
    case proplists:get_value(<<"type">>, Doc) of
    undefined ->
        ok;
    Type ->
        Identifiers = proplists:get_value(<<"identifiers">>, Doc),
        ID = proplists:get_value(<<"_id">>, Doc),
        Username = proplists:get_value(<<"username">>, Doc),
        Name = proplists:get_value(<<"name">>, Doc),
        lists:foreach(fun(Identifier) -> Emit(Identifier, [ID, Username, Name]) end, Identifiers);
    _ ->
        ok
    end
end.

which emits:

{"total_rows":3,"offset":0,"rows":[
{"id":"user-1","key":"ABC","value":["monkey","Monkey Man"]},
{"id":"user-1","key":"DEF","value":["monkey","Monkey Man"]},
{"id":"user-1","key":"123","value":["monkey","Monkey Man"]}
]}

The question is - how can I get those values out as tuples, instead of as arrays? I don't imagine I can (or would want to) use records, but using atoms in a tuple doesn't seem to work.

lists:foreach(fun(Identifier) -> Emit(Identifier, {id, ID, username, Username, name, Name}) end, Identifiers);

Fails with the following error:

{"error":"json_encode","reason":"{bad_term,{<<\"user-1\">>,<<\"monkey\">>,<<\"Monkey Man\">>}}"}

Thoughts? I know that Erlang sucks for this specific kind of thing (named access) and that I can do it by convention (id at first position, username next, real name last), but that makes the client side code pretty ugly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黯然 2024-08-31 17:26:39

JSON 对象 {"foo":"bar","baz":1}{[{<<"foo">>,<<"bar ">>},{<<"baz">>,1}]}

在 Erlang 语言中,它是包裹在元组中的 proplist。

它并不漂亮,但非常高效:)

要感受一下它,您可以使用 CouchDB 附带的 JSON 库:

  1. 使用 -i 启动 CouchDB
    (交互式)标志
  2. 在生成的 erlang shell 上,输入:couch_util:json_decode(<<"{\"foo\":\"bar\"}">>)。
  3. Profit

/ / 在 CouchDB 的更高版本中,这是 ejson:decode()

The JSON object {"foo":"bar","baz":1} is {[{<<"foo">>,<<"bar">>},{<<"baz">>,1}]}

In Erlang lingua it is a proplist wrapped in a tuple.

It's not pretty, but very efficient :)

To get a feel for it you can play with the JSON lib that ships with CouchDB:

  1. Start CouchDB with the -i
    (interactive) flag
  2. On the resulting erlang shell, type: couch_util:json_decode(<<"{\"foo\":\"bar\"}">>).
  3. Profit

// in later versions of CouchDB, this is ejson:decode()

望笑 2024-08-31 17:26:39

对于 test_suite_reports bd,它有 tests 字段:

[
   {
       "name": "basics",
       "status": "success",
       "duration": 21795
   },
   {
       "name": "all_docs",
       "status": "success",
       "duration": 385
   } ...

我写了这个来获取名称和状态:

fun({Doc}) ->
  Name = fun(L) ->  proplists:get_value(<<"name">>, L, null) end,
  Status = fun(L) -> proplists:get_value(<<"status">>, L, null) end,
  Tests = proplists:get_value(<<"tests">>, Doc, null),
  lists:foreach(fun({L}) -> Emit(Name(L), Status(L)) end, Tests)
end.

For test_suite_reports bd, that has tests field:

[
   {
       "name": "basics",
       "status": "success",
       "duration": 21795
   },
   {
       "name": "all_docs",
       "status": "success",
       "duration": 385
   } ...

I have wrote this to get name and status:

fun({Doc}) ->
  Name = fun(L) ->  proplists:get_value(<<"name">>, L, null) end,
  Status = fun(L) -> proplists:get_value(<<"status">>, L, null) end,
  Tests = proplists:get_value(<<"tests">>, Doc, null),
  lists:foreach(fun({L}) -> Emit(Name(L), Status(L)) end, Tests)
end.
梦过后 2024-08-31 17:26:39

如果您喜欢实验性功能(仍然有效...),您可能想看看 Erlang 表达式

我发现它对于为 Erlang 创建某种动态记录非常有帮助。

If you like experimental features (that still work...), you might want to have a look to Erlang exprecs.

I found it extremely helpful in creating a sort of dynamic records for Erlang.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文