Skip to content

NASA Near Earth Objects

NASA's Near Earth Object Web Service provides data about asteroids and comets that pass close to Earth. This dataset is excellent for learning jpx because it has:

  • Deeply nested data structures
  • Multiple unit systems (km, miles, AU, lunar distances)
  • Boolean flags for hazard classification
  • Time series data (close approach dates)
  • Complex orbital mechanics data

Getting the Data

# Browse all NEOs (paginated)
curl -s "https://api.nasa.gov/neo/rest/v1/neo/browse?api_key=DEMO_KEY" > neo_browse.json

# Get NEOs by close approach date (today)
curl -s "https://api.nasa.gov/neo/rest/v1/feed?api_key=DEMO_KEY" > neo_feed.json

# Get specific date range
curl -s "https://api.nasa.gov/neo/rest/v1/feed?start_date=2024-01-01&end_date=2024-01-07&api_key=DEMO_KEY" > neo_week.json

# Look up specific asteroid
curl -s "https://api.nasa.gov/neo/rest/v1/neo/2000433?api_key=DEMO_KEY" > eros.json

Note: Use DEMO_KEY for testing (limited rate). Get a free API key at api.nasa.gov.

Data Structure

The browse endpoint returns:

{
  "links": {"self": "...", "next": "..."},
  "page": {
    "size": 20,
    "total_elements": 41839,
    "total_pages": 2092,
    "number": 0
  },
  "near_earth_objects": [
    {
      "id": "2000433",
      "name": "433 Eros (A898 PA)",
      "name_limited": "Eros",
      "nasa_jpl_url": "https://ssd.jpl.nasa.gov/...",
      "absolute_magnitude_h": 10.38,
      "estimated_diameter": {
        "kilometers": {"estimated_diameter_min": 22.31, "estimated_diameter_max": 49.89},
        "meters": {...},
        "miles": {...},
        "feet": {...}
      },
      "is_potentially_hazardous_asteroid": false,
      "close_approach_data": [
        {
          "close_approach_date": "2024-01-15",
          "relative_velocity": {
            "kilometers_per_second": "5.57",
            "kilometers_per_hour": "20083.02",
            "miles_per_hour": "12478.81"
          },
          "miss_distance": {
            "astronomical": "0.314",
            "lunar": "122.5",
            "kilometers": "47112732",
            "miles": "29274494"
          },
          "orbiting_body": "Earth"
        }
      ]
    }
  ]
}

Basic Queries

List Asteroid Names

jpx 'near_earth_objects[*].name' neo_browse.json

Get Short Names

jpx 'near_earth_objects[*].name_limited' neo_browse.json

Output:

["Eros", "Albert", "Alinda", "Ganymed", ...]

Count NEOs in Response

jpx 'page.total_elements' neo_browse.json

Output: 41839 (total known NEOs!)


Filtering

Find Potentially Hazardous Asteroids (PHAs)

jpx 'near_earth_objects[?is_potentially_hazardous_asteroid == `true`].{
  name: name_limited,
  diameter_km: estimated_diameter.kilometers.estimated_diameter_max
}' neo_browse.json

Find Large Asteroids (> 1km)

jpx 'near_earth_objects[?estimated_diameter.kilometers.estimated_diameter_max > `1`].{
  name: name,
  max_diameter_km: estimated_diameter.kilometers.estimated_diameter_max,
  hazardous: is_potentially_hazardous_asteroid
}' neo_browse.json

Find Non-Hazardous Objects

jpx 'near_earth_objects[?is_potentially_hazardous_asteroid == `false`].name_limited' neo_browse.json

Working with Nested Data

Extract Diameter Estimates

The API provides diameters in multiple units:

jpx 'near_earth_objects[*].{
  name: name_limited,
  min_km: estimated_diameter.kilometers.estimated_diameter_min,
  max_km: estimated_diameter.kilometers.estimated_diameter_max
}' neo_browse.json

Calculate Average Diameter

jpx 'near_earth_objects[*].{
  name: name_limited,
  avg_diameter_km: divide(
    add(
      estimated_diameter.kilometers.estimated_diameter_min,
      estimated_diameter.kilometers.estimated_diameter_max
    ),
    `2`
  )
}' neo_browse.json

Get Diameter in Different Units

jpx 'near_earth_objects[0].{
  name: name,
  in_km: estimated_diameter.kilometers,
  in_meters: estimated_diameter.meters,
  in_miles: estimated_diameter.miles
}' neo_browse.json

Close Approach Data

Get Next Close Approach

jpx 'near_earth_objects[*].{
  name: name_limited,
  next_approach: close_approach_data[0].close_approach_date,
  miss_distance_km: close_approach_data[0].miss_distance.kilometers
}' neo_browse.json

Find Closest Approaches (in Lunar Distances)

One lunar distance = 384,400 km (distance to the Moon):

jpx 'near_earth_objects[*].close_approach_data[*].{
  asteroid: @.@.@.name_limited,
  date: close_approach_date,
  lunar_distances: miss_distance.lunar
} | flatten(@)' neo_browse.json

Sort by Miss Distance

jpx 'near_earth_objects[*].{
  name: name_limited,
  miss_km: to_number(close_approach_data[0].miss_distance.kilometers)
} | sort_by(@, &miss_km) | [:10]' neo_browse.json

Find High-Speed Approaches

jpx 'near_earth_objects[*].{
  name: name_limited,
  speed_kph: to_number(close_approach_data[0].relative_velocity.kilometers_per_hour),
  date: close_approach_data[0].close_approach_date
} | [?speed_kph > `50000`]' neo_browse.json

Statistics

Size Statistics

jpx '{
  count: length(near_earth_objects),
  smallest_km: min(near_earth_objects[*].estimated_diameter.kilometers.estimated_diameter_min),
  largest_km: max(near_earth_objects[*].estimated_diameter.kilometers.estimated_diameter_max),
  avg_max_km: round(avg(near_earth_objects[*].estimated_diameter.kilometers.estimated_diameter_max), `2`)
}' neo_browse.json

Hazard Statistics

jpx '{
  total: length(near_earth_objects),
  hazardous: length(near_earth_objects[?is_potentially_hazardous_asteroid == `true`]),
  safe: length(near_earth_objects[?is_potentially_hazardous_asteroid == `false`]),
  hazard_percentage: multiply(
    divide(
      length(near_earth_objects[?is_potentially_hazardous_asteroid == `true`]),
      length(near_earth_objects)
    ),
    `100`
  )
}' neo_browse.json

Magnitude Distribution

Absolute magnitude (H) indicates brightness/size:

jpx '{
  magnitudes: near_earth_objects[*].absolute_magnitude_h,
  min_mag: min(near_earth_objects[*].absolute_magnitude_h),
  max_mag: max(near_earth_objects[*].absolute_magnitude_h),
  avg_mag: round(avg(near_earth_objects[*].absolute_magnitude_h), `2`)
}' neo_browse.json

Sorting and Ranking

Top 5 Largest Asteroids

jpx 'sort_by(near_earth_objects, &estimated_diameter.kilometers.estimated_diameter_max) 
  | reverse(@) 
  | [:5] 
  | [*].{
      name: name,
      max_diameter_km: round(estimated_diameter.kilometers.estimated_diameter_max, `2`),
      hazardous: is_potentially_hazardous_asteroid
    }' neo_browse.json

Brightest Objects (Lowest Magnitude)

jpx 'sort_by(near_earth_objects, &absolute_magnitude_h) | [:5] | [*].{
  name: name_limited,
  magnitude: absolute_magnitude_h,
  diameter_km: estimated_diameter.kilometers.estimated_diameter_max
}' neo_browse.json

Unit Conversions

Convert AU to Kilometers

1 AU (Astronomical Unit) = ~149,597,870.7 km:

jpx 'near_earth_objects[*].{
  name: name_limited,
  miss_au: to_number(close_approach_data[0].miss_distance.astronomical),
  miss_km: to_number(close_approach_data[0].miss_distance.kilometers)
}' neo_browse.json

Velocity Comparisons

jpx 'near_earth_objects[*].{
  name: name_limited,
  km_per_sec: to_number(close_approach_data[0].relative_velocity.kilometers_per_second),
  km_per_hour: to_number(close_approach_data[0].relative_velocity.kilometers_per_hour),
  mph: to_number(close_approach_data[0].relative_velocity.miles_per_hour)
}' neo_browse.json

Data Transformation

Flatten for Analysis

jpx 'near_earth_objects[*].{
  id: id,
  name: name_limited,
  magnitude: absolute_magnitude_h,
  diameter_min_km: estimated_diameter.kilometers.estimated_diameter_min,
  diameter_max_km: estimated_diameter.kilometers.estimated_diameter_max,
  is_hazardous: is_potentially_hazardous_asteroid,
  next_approach_date: close_approach_data[0].close_approach_date,
  miss_distance_km: close_approach_data[0].miss_distance.kilometers,
  velocity_kph: close_approach_data[0].relative_velocity.kilometers_per_hour,
  jpl_url: nasa_jpl_url
}' neo_browse.json

Export to CSV

jpx --csv 'near_earth_objects[*].{
  name: name_limited,
  magnitude: absolute_magnitude_h,
  max_diameter_km: estimated_diameter.kilometers.estimated_diameter_max,
  is_hazardous: is_potentially_hazardous_asteroid,
  approach_date: close_approach_data[0].close_approach_date
}' neo_browse.json

Advanced Pipelines

Risk Assessment Report

jpx '{
  report_title: `Near Earth Object Risk Assessment`,
  total_objects: page.total_elements,
  sample_size: length(near_earth_objects),
  potentially_hazardous: {
    count: length(near_earth_objects[?is_potentially_hazardous_asteroid == `true`]),
    objects: near_earth_objects[?is_potentially_hazardous_asteroid == `true`] | [*].{
      name: name,
      diameter_km: round(estimated_diameter.kilometers.estimated_diameter_max, `2`),
      next_approach: close_approach_data[0].close_approach_date,
      miss_lunar: close_approach_data[0].miss_distance.lunar
    }
  },
  largest_objects: sort_by(near_earth_objects, &estimated_diameter.kilometers.estimated_diameter_max) 
    | reverse(@) 
    | [:3] 
    | [*].{name: name_limited, km: round(estimated_diameter.kilometers.estimated_diameter_max, `1`)}
}' neo_browse.json

Pipeline: Filter, Sort, Transform

jpx 'near_earth_objects
  | [?estimated_diameter.kilometers.estimated_diameter_max > `0.5`]
  | [?is_potentially_hazardous_asteroid == `true`]
  | sort_by(@, &estimated_diameter.kilometers.estimated_diameter_max)
  | reverse(@)
  | [*].{
      name: name,
      size_category: `LARGE PHA`,
      diameter_range: concat(
        to_string(round(estimated_diameter.kilometers.estimated_diameter_min, `1`)),
        ` - `,
        to_string(round(estimated_diameter.kilometers.estimated_diameter_max, `1`)),
        ` km`
      )
    }' neo_browse.json

Working with the Feed Endpoint

The feed endpoint returns NEOs by date:

curl -s "https://api.nasa.gov/neo/rest/v1/feed?start_date=2024-01-15&end_date=2024-01-16&api_key=DEMO_KEY" > neo_day.json

Count by Date

jpx 'element_count' neo_day.json

List All Dates with Objects

jpx 'keys(near_earth_objects)' neo_day.json

Get Objects for Specific Date

jpx 'near_earth_objects."2024-01-15"[*].name' neo_day.json

Using Query Libraries

Instead of typing these queries repeatedly, save them in a .jpx query library. See examples/nasa-neo.jpx for a ready-to-use library:

# List available queries
jpx -Q examples/nasa-neo.jpx --list-queries

# Run common analyses
jpx -Q examples/nasa-neo.jpx:hazardous neo_browse.json
jpx -Q examples/nasa-neo.jpx:risk-report neo_browse.json
jpx -Q examples/nasa-neo.jpx:top-5-largest neo_browse.json

# Output as table
jpx -Q examples/nasa-neo.jpx:closest-approaches -t neo_browse.json

See Query Files for more on creating and using query libraries.


Try It Yourself

  1. Get your free API key: api.nasa.gov

  2. Interesting queries to try:

  3. Find the closest approach ever recorded
  4. List all PHAs larger than 500 meters
  5. Calculate average velocity of approaching objects

  6. API endpoints:

  7. /neo/browse - Paginated list of all NEOs
  8. /neo/rest/v1/feed - NEOs by approach date
  9. /neo/{id} - Specific asteroid details

  10. API Documentation: NASA NEO API