-2

Wondering what the best way is to break a large data object coming from AJAX apart. If I send just one portion (says paths) I use JSON.parse(data) What I'd really like to do is split the object apart first into it's individual blocks, then be able to do something like JSON.parse(data['paths']).

Here's a clipped sample of the JSON data

{
    "paths": {
        "type": "FeatureCollection",
        "features": [{
            "type": "Feature",
            "geometry": {
                "type": "MultiLineString",
                "coordinates": [
                    [
                        [-122.32074805731085, 47.634990818586026],
                        [-122.32074412999432, 47.63497931696752],
                        [-122.32107629703529, 47.63465666282262]
                    ]
                ]
            },
            "properties": {
                "path_name": "Woodland path"
            },
            "id": 2
        }]
    },
    "beds": {
        "type": "FeatureCollection",
        "features": [{
            "type": "Feature",
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [-122.32073753862116, 47.6347629704532],
                            [-122.32071585642394, 47.63470617810399],
                            [-122.32073753862116, 47.6347629704532]
                        ]
                    ]
                ]
            },
            "properties": {
                "bed_name": "Azalea Triangle"
            },
            "id": 1
        }]
    }
}

Here's what I have in javascript

   $.ajax
    dataType: 'text'
    url: 'map.json'
    success: (data) ->

Here's the Rails code that generates the call

    data = { buildings: @geopaths, lawns: @geobeds }

respond_to do |format|
  format.json { render json: data }
  format.html
end

UPDATE: I had sort of avoided explaining what I was wanting to do because I thought it would confuse the issue. In a nut shell - I am collecting data from a database, and sending it to Javascript to be displayed as layers on a map. Each layer has a name (paths, beds, etc), and gets encoded as GeoJSON in Rails before being sent to Javascript with an AJAX command. If I only send one layer I have no trouble parsing the data and getting it onto the map. A typical line of code would look like pathMarkers = L.geoJSON(JSON.parse(data)).

I now need to pass multiple layers to the map. My understanding is AJAX can only handle one object so I combine both paths and beds into one object. When I get to the Javascript side I don't know what to do. In other words I need to get only that portion of the object that has path data for the pathMarkers, and only that portion of the object that has bed data for the bedMarkers.

Graphically this is what I'm trying to do:

paths = a bunch of GeoJSON data
beds = a bunch of GeoJSON data
Use AJAX to send paths and beds to javascript
build pathMarkers with JSON.parse for the paths data
build bedsMarkers with JSON.parse for the beds data

I could build a sample and post it to bitbucket if it would help.

Ben
  • 367
  • 1
  • 5
  • 19
  • 2
    That doesn't make sense. You can only access individual parts of the object after you parsed the JSON. E.g. `JSON.parse(data).paths`. – Felix Kling Nov 07 '16 at 22:56
  • Perhaps that the root of my issue - I'm confused. :) – Ben Nov 07 '16 at 23:00
  • Maybe this helps: [Access / process (nested) objects, arrays or JSON](http://stackoverflow.com/q/11922383/218196) – Felix Kling Nov 07 '16 at 23:02
  • Why do you need to break it up? If the parsing is going slow, see if you can split the service calls apart so that, for instance, you make a call for `paths`, then a call for `beds`, or whatever... – Heretic Monkey Nov 07 '16 at 23:03
  • No, breaking one json string into multiple isn't a great idea. Just parse it to a js object/array and then break it apart there. – Kevin B Nov 07 '16 at 23:12
  • Thanks @FelixKling that post looks very helpful. – Ben Nov 07 '16 at 23:14
  • @Ben Key question: **why** do you believe you _need to split_ the object? What is your concern? What are you trying to achieve? Answering these will help us help you. – tmslnz Nov 07 '16 at 23:52
  • @tmslnz I've updated my question - I hope it helps – Ben Nov 08 '16 at 00:46

2 Answers2

1

I've run into this problem before with incredibly large payloads on mobile devices (iOS with Phonegap, to be precise). You may want to look into a library named OboeJS, at http://www.juancaicedo.com/oboe.js-website/.

Essentially, that library streams the JSON request so that you can process it in chunks. You should be able to use this to suit your needs.

1

Assuming that I understood correctly and your concern is bringing in distinct data layers into a geo library like Leaflet.js, a single AJAX request is fine unless the JSON payload is so large that it crashes the browser.

As you don't provide much of your code, the following is a general example of how you would do it.

First you create the map object. Obviously :)

const map = L.map(id).setView([1.2345, -1.2345], 10);

Start the AJAX request to fetch the geoJSON file.

$.ajax({
  dataType: "json",
  url: '/json/lives/here.json',
  data: {} /* any props you'd like to pass as query string to your server */,
  success: success
});

And the crux of the issue: "How do I access each feature collection?"
The sucess or done callback is where you can be sure you received the data, and can add it to the map.

jQuery's AJAX method, when called with dataType: 'json', automatically runs JSON.parse() for you (and a couple of other things). Once the JSON is parsed, it can be accessed as any other object in JS. At this point the success callback receives the JSON-turned-into-object, which you can access with traditional JS methods. Like so:

function success (data) {
    // data is the parsed JSON. It is now just a JS object.
    // Below: for every "key" in the data object, pass its data to L.geoJSON() and add it to the map.
    for (var geojsonFeatureCollection in data) {
        if (data.hasOwnProperty(geojsonFeatureCollection)) {
            L.geoJSON(geojsonFeatureCollection, {/* options */}).addTo(map);
        }
    }
}

To answer your point about AJAX and a single object: AJAX is a just like any other browser request.
Yes you do send one request at a time. And likewise you receive one response from the server. But what is contained in the response can be absolutely any data. So what you are doing server side is totally OK!

In your case the data consists of a JSON text file, which is later parsed and turned into a JS object for you to actually do something with. The object contains a bunch of "keys" (beds, paths) and all you need to do is iterate over each of those keys and pass each one to Leaflet's geoJSON method for rendering.

tmslnz
  • 1,801
  • 2
  • 15
  • 24
  • WOW! Thanks a ton @tmslnz for making a gourmet meal out of my scrambled eggs. :) You are right on track with that I was trying to do. Happy to share any code that's helpful. I did notice that some JS didn't format correctly above so I fixed that. I tried to drop your code in, but I must be missing some concept all I get is "Uncaught Error: Invalid GeoJSON object". I'm working on building a simple demo to place on bitbucket, but if posting code is easier let me know. – Ben Nov 08 '16 at 23:28
  • "Invalid GeoJSON" sounds like your server is screwing it up – tmslnz Nov 09 '16 at 07:42
  • From what I can tell from console.dig the geofeaturecollection contains just the name of the feature - no data. [url=https://postimg.org/image/kphro68vn/][img]https://s21.postimg.org/kphro68vn/Untitled.png[/img][/url] – Ben Nov 09 '16 at 15:08