Created
February 8, 2014 20:08
-
-
Save mhkeller/8889450 to your computer and use it in GitHub Desktop.
SQL-like left joins in JavaScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var _ = require('underscore'); | |
var geo_key = 'name', | |
value_key = 'state_name'; | |
var geo_data = [ | |
{ | |
"name": 'AK', | |
"geom": '1' | |
}, | |
{ | |
"name": 'CA', | |
"geom": '2' | |
}, | |
{ | |
"name": 'NY', | |
"geom": '3' | |
}, | |
{ | |
"name": 'LA', | |
"geom": '4' | |
} | |
] | |
var value_data = [ | |
{ | |
"state_name": 'AK', | |
"awesomeness": '1', | |
"coldness": 200 | |
}, | |
{ | |
"state_name": 'CA', | |
"awesomeness": '100' | |
}, | |
{ | |
"state_name": 'NY', | |
"awesomeness": '75' | |
} | |
] | |
function addNulls(data, null_key_obj){ | |
data.forEach(function(datum){ | |
// Create copies of our objects so they dont' get overwritten | |
var null_key_obj_persist = _.extend({}, null_key_obj), | |
datum_persist = _.extend({}, datum); | |
// You could extend `null_key_obj_persist` with `datum` but that would reverse the order of your keys | |
// And always put your keys that have nulls (which are probably the least important keys) first. | |
// This way will overwrite everything with nulls, then rewrite keys that have values. | |
_.extend(datum, null_key_obj_persist, datum_persist) | |
}) | |
return data | |
} | |
function addToNullMatch(key_map, keys){ | |
keys.forEach(function(key){ | |
if (!key_map.null_match[key]){ | |
key_map.null_match[key] = null | |
} | |
}) | |
} | |
function indexRightDataOnKey(right_data, right_key_column){ | |
var key_map = { | |
null_match: {} | |
}; | |
right_data.forEach(function(datum){ | |
var right_key_value = datum[right_key_column]; | |
if (!key_map[right_key_value]){ | |
// Get rid of the original name key since that will just be a duplicate | |
delete datum[right_key_column]; | |
key_map[right_key_value] = datum; | |
// Log the new keys that we've encountered for a comprehensive list at the end | |
addToNullMatch(key_map, _.keys(datum)); | |
}else{ | |
throw new Error('Duplicate entry for "' + right_key_value + '"'); | |
} | |
}) | |
return key_map | |
} | |
function joinOnMatch(left_data, left_key_column, key_map){ | |
left_data.forEach(function(datum){ | |
var key = datum[left_key_column], | |
match = key_map[key]; | |
if (match){ | |
_.extend(datum, match); | |
} | |
}) | |
return left_data | |
} | |
function joinData(left_data, left_key_column, right_data, right_key_column){ | |
var key_map = indexRightDataOnKey(right_data, right_key_column), | |
joined_data = joinOnMatch(left_data, left_key_column, key_map), | |
joined_data_w_nulls = addNulls(joined_data, key_map.null_match); | |
return joined_data_w_nulls; | |
} | |
var joined_data = joinData(geo_data, geo_key, value_data, value_key) | |
console.log(joined_data) | |
/* | |
[ { name: 'AK', geom: '1', awesomeness: '1', coldness: 200 }, | |
{ name: 'CA', geom: '2', awesomeness: '100', coldness: null }, | |
{ name: 'NY', geom: '3', awesomeness: '75', coldness: null }, | |
{ name: 'LA', geom: '4', awesomeness: null, coldness: null } ] | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment