Perform JOIN operations on two data arrays with D3.js

3

I'm preparing the data for viewing and viewing operations. I use the library D3.js .

The data collection is:

{ "autores" : [
  { "id":1, "nome": "Fulano" },
  { "id":2, "nome": "Ciclano" }
  ],
  "livros" : [
    {"id": 1, "autor": 1, "titulo": "AAA" },
    {"id": 2, "autor": 1, "titulo": "BBB" },
    {"id": 3, "autor": 2, "titulo": "CCC" },
    {"id": 4, "autor": 2, "titulo": "XXX" },
    {"id": 5, "autor": 2, "titulo": "YYY" }
  ]
}

The operation has to act similar to a JOIN in the SQL command, obtaining the following result as a response:

[
  {"id":1, "autor": { "id": 1, "nome": "Fulano" }, "titulo": "AAA" },
  {"id":2, "autor": { "id": 1, "nome": "Fulano" }, "titulo": "BBB" },
  {"id":3, "autor": { "id": 2, "nome": "Ciclano" }, "titulo": "CCC" },
  {"id":4, "autor": { "id": 2, "nome": "Ciclano" }, "titulo": "XXX" },
  {"id":5, "autor": { "id": , "nome": "Ciclano" }, "titulo": "YYY" },
]

Is there any way to do this by using the D3.js library?

    
asked by anonymous 12.11.2014 / 15:03

1 answer

5

If you are just trying to generate this final array from the two initial arrays, just do a second mapping with the first, and for that you do not need any additional libraries. Here are suggestions for solutions:

1) For each book, make an in-place replacement by filtering the correct author.

livros.forEach(function(d){ d.autor = autores.filter(function(g){ return g.id === d.autor })[0] });

This solution has cost O (books * authors), because for each book, a scan in the authors array performed (triggered by the filter function). We can improve ...

2) Index authors by id and iterate over books by making in-place substitutions.

// Indexa autores
var autorMap = {};
autores.forEach(function(d){ autorMap[d.id] = d });
// Realiza substituição
livros.forEach(function(d){ d.autor = autorMap[d.autor] });

This solution has cost O (books + authors), because it first iterates over the authors by indexing them, and then iterates over the books by performing the substitution through a query to constant cost.

For your safety, I suggest a slightly different final solution ...

3) Index the authors by id and iterate over the books, cloning them securely, and returning a new array.

// Indexa autores
var autorMap = {};
autores.forEach(function(d){ autorMap[d.id] = d });
// Mapeia os livros para um novo array com livros modificados
var newArr = livros.map(function(d){ var c = deepCopy(d); c.autor = autorMap[d.autor]; return c });

To understand more about these functions I've demonstrated (forEach, filter, map) see Mozilla official documentation . Including D3 itself encourage this .

Regarding the join that was considered in the question, it is worth considering what the join really means for D3. In Mike's excellent article, "Thiking with Joins" , we read:

  Thinking with joins means declaring the relationship between a selection (such as "circle") and data, and then implementing this relationship through the three enter , update and < in> exit states.

Notice that join defines not only a relationship between selections (DOM elements) and data (js arrays, objects, etc) , as well as the form as this relationship is processed (through three sequential states).

That is, this is more related to a high-level pattern of manipulation of elements-better, document-than to a low-level technique of data processing. There's even a name for it: Data-Driven Documents

So, if you are looking for point solutions to problems handling objects, arrays, or data in general, you should first think about how to achieve this using native js only, and then look for some library that provides utilities (such as < a href="http://underscorejs.org/"> underscore.js ). Otherwise, if you're looking for a new paradigm of how to manipulate documents (other than jQuery, for example), D3 is the answer. And you still get a huge diversity of toast utilities! ;)

    
12.11.2014 / 18:26