简体   繁体   中英

Rethinkdb Array of Object to Object of Array

I'm trying to work with Rethinkdb in mapreducing something like: [{"a":1, "b":2}, {"a":3}, {"c":4}] to {"a":[1,3], "b":[2], "c":[4]} .

I have already consulted Javascript: How convert array of objects to object with sorted unique arrays? but the statements doesn't really work in ReQL, here's an example:

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
});

but this faults out on itm(p) with the error: 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"))}; }) ^^^^^^^ 

because rethinkdb is assigning variable id (137 in this case) to the itm(p) that's not declared beforehand.

Any ideas how i can do this?

Thanks

Adapting an answer from danielmewes on github

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');

Since this uses some advanced ReQL techniques, here's how it breaks down:

  1. First we grab the keys of every object in the array. This results in an array of arrays
  2. Next we reduce, this does a pairwise combination of elements from the previous array of arrays. What we end up with is a deduplicated list of all keys in any of the objects in the original array.
  3. Next, for each key, we create a two element array where the first element is the key, and the second element is an array of all of the values in the original input with that key.
    • this works because () in reql is more powerful than regular javascript [] brackets. It will collect the values of the field with that key.
    • the output of this step is an array of arrays like [['a', [1,2]], ['b', [3,4]]
  4. Finally, we coerce to an object. ReQL can coerce arrays like [['a', 1], ['b', 2]] into the object {a: 1, b: 2} , which is really useful here.

Here's the answer (or one way to do it), if anyone's wondering...

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; })"
))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM