Perform JOIN operations on two data arrays with D3.js

Asked

Viewed 82 times

3

I am preparing the data for visualization and visualization operations. I use the library D3.js.

The collection of data 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 the answer:

[
  {"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?

1 answer

5


If you are just trying to generate this final array from the two initial arrays, just do a mapping of the second one with the first one, and no additional library is required for this. Follows suggestions of solutions:

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

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

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

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

// 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 The(books + authors), because first iterate on the authors by indexing them, and then iterate on the books by performing the substitution through a consultation at 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 demonstrated (foreach, filter, map) see official documentation of Mozilla. Including the D3 itself encourages this.

With respect to Join which was considered in question, it is worth considering what actually means Join for D3. In Mike’s excellent article, "Thiking with Joins", we read:

Thinking with joins Means declaring a Relationship between a Selection (such as "Circle") and data, and then implementing this Relationship through the three enter, update and Exit States.

Realize that the Join defines not only a relationship between selections (elements of the FOD) and dice (js arrays, Objects, etc.), as mainly the form how this relationship is processed (through three sequential states).

That is, this is more related to a high-level standard of element handling -better, document - than to a low-level data processing technique. There’s even a name for it: Data-Driven Documents

So, if you are looking for point solutions to object handling problems, arrays or data in general, you should first think about how to achieve this using native js only, and then search for some library that provides utilities (such as underscore.js). Otherwise, if you are looking for a new paradigm of how to manipulate documents (unlike jQuery, for example), D3 is the answer. And you still get a huge diversity of free utilities! ;)

  • Excellent article Thinking with Joins, is a key part of understanding D3.

  • A pity that D3 does not implement arrays manipulation, or 'date', is essential in its operation. By the way, why D3 does not implement a cyclic search on your D3.selection.data =\

  • D3 implements several interesting array manipulations ( see Array Operators), but it does not reimplementate solutions already native. This need that you exposed would be an interesting solution to have on the menu. Maybe it’s worth suggesting in the community.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.