Analog to SQL 'JOIN' for Javascript objects?
You can do it with Alasql JavaScript SQL library:
var res = alasql('SELECT * FROM ? authors \
LEFT JOIN ? books ON authors.id = books.author_id',[authors, books]);
Try this example with your data in jsFiddle.
Also you can load CSV data directly into SQL expression:
alasql('SELECT * FROM CSV("authors.csv", {headers:true}) authors \
LEFT JOIN CSV("books.csv", {headers:true}) books \
ON authors.id = books.author_id',[], function(res) {
console.log(res);
});
Basically, like this:
// first, build an easier lookup of author data:
var authormap = {};
authors.forEach(function(author) {authormap[author.id] = author;});
// now do the "join":
books.forEach(function(book) {
book.author = authormap[book.author_id];
});
// now you can access:
alert(books[0].author.name);
I was looking for something like this as well, and solved it using a bit of functional programming. I've taken the liberty of adding a couple of objects to your initial arrays in order to deal with the "NULL" cases.
var books = [
{author_id: 1, title: 'Coloring for beginners'},
{author_id: 1, title: 'Advanced coloring'},
{author_id: 2, title: '50 Hikes in New England'},
{author_id: 2, title: '50 Hikes in Illinois'},
{author_id: 3, title: 'String Theory for Dummies'},
{author_id: 5, title: 'Map-Reduce for Fun and Profit'}
];
var authors = [
{id: 1, name: 'adam'},
{id: 2, name: 'bob'},
{id: 3, name: 'charlie'},
{id: 4, name: 'diane'}
];
So now you have a book without an author and an author without a book. My solution looks like this:
var joined = books.map(function(e) {
return Object.assign({}, e, authors.reduce(function(acc, val) {
if (val.id == e.author_id) {
return val
} else {
return acc
}
}, {}))
});
The map method goes through every element of books
using e
and returns an array whose elements are the merged object of e
, with its corresponding object in the authors
array. Object.assign({},a,b)
takes care the merge without modifying the original objects.
The corresponding object to each e
in books
is found by applying a reduce method on the authors
array. Starting out with the initial value of an empty object {}
(this is the second argument of reduce - it also could have been a null author such as {id:'', name ''}
) the reduce method goes through the elements of authors
using val
and returns the object that ends up in acc
. When a match is found between the books author_id
and the author's id
the entire matched author object ends up in acc
and eventually gets returned by authors.reduce(...)
.
n.b. - Using reduce isn't that efficient because there is no way to break out of reduce loop once the match is found, it will continue to the end of the array