Rethinkdb 对象数组到数组对象
Rethinkdb Array of Object to Object of Array
我正在尝试与 Rethinkdb 合作进行 mapreducing,例如:
[{"a":1, "b":2}, {"a":3}, {"c":4}]
到 {"a":[1,3], "b":[2], "c":[4]}
.
我已经咨询过 Javascript: How convert array of objects to object with sorted unique arrays? 但这些语句在 ReQL 中并不真正起作用,这里有一个例子:
r.expr([{"a":1, "b":2}, {"a":3}, {"c":4}]).do(function(user){
var c1 = {};
var keys = ["a", "b", "c"];
user.map(function(itm){
keys.map(function(p){
if(!c1[p]){
c1[p] = [];
};
c1[p] = r.expr(c1[p]).setInsert(itm(p).default("NIL"));
});
return 1
});
return c1
});
但这会在 itm(p) 上出现错误:RqlCompileError: Variable name not found in:
RqlCompileError: Variable name not found in:
r([{a: 1, b: 2}, {a: 3}, {c: 4}]).do(function(var_136) { return {a: r([]).setInsert(var_137("a").default("NIL")), b: r([]).setInsert(var_137("b").default("NIL")), c: r([]).setInsert(var_137("c").default("NIL"))}; })
^^^^^^^
因为 rethinkdb 正在将变量 id(在本例中为 137)分配给事先未声明的 itm(p)。
有什么办法可以做到这一点吗?
谢谢
这是答案(或一种方法),如果有人想知道...
r.expr([{"a":1, "b":2}, {"a":3}, {"c":4}]).do( r.js("(function(input){
var keys=['a','b','c'], output={};
input.forEach(function(e){
for(var p in e){
output[p] = (output[p] || []).concat(e[p]);
} });
return output; })"
))
的答案
var input = r.expr([{"a":1}, {"a":3}, {b: 2}, {"a":4}, {b: 3}]);
var keys = input.map(function(x){return x.keys()})
.reduce(function(l, r){return l.setUnion(r)});
.map(function(key){ return [key, input(key)]})
.coerceTo('object');
由于它使用了一些高级 ReQL 技术,因此分解如下:
- 首先我们获取数组中每个对象的键。这导致数组数组
- 接下来我们归约,这对来自
以前的数组数组。我们最终得到的是原始数组中任何对象中所有键的去重列表。
- 接下来,对于每个键,我们创建一个双元素数组,其中第一个元素是键,第二个元素是原始输入中具有该键的所有值的数组。
- 这是有效的,因为 reql 中的
()
比常规的 javascript []
括号更强大。它将使用该键收集字段的值。
- 这一步的输出是一个数组数组,如
[['a', [1,2]], ['b', [3,4]]
- 最后,我们强制转换到一个对象。 ReQL 可以将
[['a', 1], ['b', 2]]
这样的数组强制转换为对象 {a: 1, b: 2}
,这在这里非常有用。
我正在尝试与 Rethinkdb 合作进行 mapreducing,例如:
[{"a":1, "b":2}, {"a":3}, {"c":4}]
到 {"a":[1,3], "b":[2], "c":[4]}
.
我已经咨询过 Javascript: How convert array of objects to object with sorted unique arrays? 但这些语句在 ReQL 中并不真正起作用,这里有一个例子:
r.expr([{"a":1, "b":2}, {"a":3}, {"c":4}]).do(function(user){
var c1 = {};
var keys = ["a", "b", "c"];
user.map(function(itm){
keys.map(function(p){
if(!c1[p]){
c1[p] = [];
};
c1[p] = r.expr(c1[p]).setInsert(itm(p).default("NIL"));
});
return 1
});
return c1
});
但这会在 itm(p) 上出现错误:RqlCompileError: Variable name not found in:
RqlCompileError: Variable name not found in:
r([{a: 1, b: 2}, {a: 3}, {c: 4}]).do(function(var_136) { return {a: r([]).setInsert(var_137("a").default("NIL")), b: r([]).setInsert(var_137("b").default("NIL")), c: r([]).setInsert(var_137("c").default("NIL"))}; })
^^^^^^^
因为 rethinkdb 正在将变量 id(在本例中为 137)分配给事先未声明的 itm(p)。
有什么办法可以做到这一点吗?
谢谢
这是答案(或一种方法),如果有人想知道...
r.expr([{"a":1, "b":2}, {"a":3}, {"c":4}]).do( r.js("(function(input){
var keys=['a','b','c'], output={};
input.forEach(function(e){
for(var p in e){
output[p] = (output[p] || []).concat(e[p]);
} });
return output; })"
))
var input = r.expr([{"a":1}, {"a":3}, {b: 2}, {"a":4}, {b: 3}]);
var keys = input.map(function(x){return x.keys()})
.reduce(function(l, r){return l.setUnion(r)});
.map(function(key){ return [key, input(key)]})
.coerceTo('object');
由于它使用了一些高级 ReQL 技术,因此分解如下:
- 首先我们获取数组中每个对象的键。这导致数组数组
- 接下来我们归约,这对来自 以前的数组数组。我们最终得到的是原始数组中任何对象中所有键的去重列表。
- 接下来,对于每个键,我们创建一个双元素数组,其中第一个元素是键,第二个元素是原始输入中具有该键的所有值的数组。
- 这是有效的,因为 reql 中的
()
比常规的 javascript[]
括号更强大。它将使用该键收集字段的值。 - 这一步的输出是一个数组数组,如
[['a', [1,2]], ['b', [3,4]]
- 这是有效的,因为 reql 中的
- 最后,我们强制转换到一个对象。 ReQL 可以将
[['a', 1], ['b', 2]]
这样的数组强制转换为对象{a: 1, b: 2}
,这在这里非常有用。