[GIS] Separating two GeoJSON files, one with properties and another with geometry

geojsonleaflet

Using Leaflet with GeoJSON, I would like to create a map with geometries, and with alphanumerical data associated to each item of the geometry. A map very similar to the easy sample at http://leafletjs.com/examples/geojson.html, with the names/values of each one the points/lines/polygons.

However, I found that, in every example I've seen, the alphanumerical data ('properties') and the geometrical data ('geometry') are within the same GeoJSON file. I mean, for each one of the items ('Features'), there are 'properties' and 'geometry' associated with the same 'id'.

I wondered if there was any possibility to separate 'properties' and 'geometry' in two different files, joining the features through their ID.

Best Answer

Thomas B and geogeek have the right idea. Here is a fiddle that takes the Leaflet sample data (which I split up into separate objects for geometry and properties), re-joins them, and displays them on a map:

http://jsfiddle.net/nathansnider/6askexjq/

The two important functions are this one (grabbed from this stackoverflow answer), to extract objects based on a key name and value:

function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            objects.push(obj);
        }
    }
    return objects;
}

and this one, to join the separate objects into a functioning GeoJSON Feature Collection:

function mergeProperties(geom, props, id) {
    //create empty feature collection for merged features
    var newgeom = {
        type: "FeatureCollection",
        features: []
    };
    //if original geometry is a feature collection, loop through all features
    if (geom.type == "FeatureCollection") {
        for (var i in geom.features) {
            var key = geom.features[i][id];
            var g = geom.features[i].geometry;
            if (key === undefined) continue;
            var p = getObjects(props, id, key);
            newgeom.features.push({
                "id": key,
                    "type": "Feature",
                    "geometry": g,
                    "properties": p[0].properties
            });
        }
    //if it's a single feature, just get the single object
    } else if (geom.type == "Feature") {
        var key = geom[id];
        var g = geom.geometry;
        if (key !== undefined) {
            var p = getObjects(props, id, key);
            newgeom.features.push({
                "id": key,
                    "type": "Feature",
                    "geometry": g,
                    "properties": p[0].properties
            });
        }
    //if it's a geometry collection (with ids within each geometry), 
    //loop through the geometries and add them as features
    } else if (geom.type == "GeometryCollection") {
        for (var i in geom.geometries) {
            var key = geom.geometries[i][id];
            var g = geom.geometries[i];
            if (key === undefined) continue;
            var p = getObjects(props, id, key);
            newgeom.features.push({
                "id": key,
                    "type": "Feature",
                    "geometry": g,
                    "properties": p[0].properties
            });
        }
    }
    return newgeom;
}

For the input geometry, it works with GeoJSON Features, Feature Collections and Geometry Collections, but adapting it for objects in other formats would not be too difficult.

Related Question