阿里云主机折上折
  • 微信号
Current Site:Index > Geospatial indexes (2d, 2dsphere)

Geospatial indexes (2d, 2dsphere)

Author:Chuan Chen 阅读数:54062人阅读 分类: MongoDB

Geospatial Indexes (2d, 2dsphere)

MongoDB provides two types of geospatial indexes: 2d and 2dsphere. The 2d index is suitable for point data on a planar coordinate system, while the 2dsphere index supports point, line, and polygon data on a spherical coordinate system. Both types of indexes can significantly improve the performance of geospatial queries.

2d Index

The 2d index is used to handle point data on a flat map and is suitable for simple two-dimensional coordinate systems. This type of index is best suited for small-scale geographic data, such as city maps or game maps.

Basic syntax for creating a 2d index:

db.collection.createIndex({ locationField: "2d" })

The 2d index supports the following query operators:

  • $near: Finds points closest to a given point
  • $geoWithin: Finds points within a specified geometric shape
  • $box: Rectangular range query
  • $center: Circular range query
  • $polygon: Polygonal range query

Example: Create a collection with location data and establish a 2d index

db.places.insertMany([
  { name: "Central Park", location: [ -73.97, 40.77 ] },
  { name: "Empire State", location: [ -73.99, 40.75 ] },
  { name: "Times Square", location: [ -73.99, 40.76 ] }
])

db.places.createIndex({ location: "2d" })

Query the 3 closest locations to a given point:

db.places.find({
  location: {
    $near: [ -73.98, 40.77 ],
    $maxDistance: 2
  }
}).limit(3)

2dsphere Index

The 2dsphere index supports more complex geospatial queries, including point, line, and polygon data. It uses the WGS84 coordinate system and is suitable for geographic data on the Earth's surface.

Basic syntax for creating a 2dsphere index:

db.collection.createIndex({ locationField: "2dsphere" })

The 2dsphere index supports the following query operators:

  • $geoWithin: Finds documents entirely contained within a specified geometric shape
  • $geoIntersects: Finds documents that intersect with a specified geometric shape
  • $near: Finds documents closest to a given point
  • $nearSphere: Similar to $near but uses spherical distance calculations

Example: Create a collection with GeoJSON data and establish a 2dsphere index

db.cities.insertMany([
  {
    name: "New York",
    location: {
      type: "Point",
      coordinates: [ -73.97, 40.77 ]
    }
  },
  {
    name: "San Francisco",
    location: {
      type: "Point",
      coordinates: [ -122.42, 37.78 ]
    }
  }
])

db.cities.createIndex({ location: "2dsphere" })

Query cities within 1000 meters of a given point:

db.cities.find({
  location: {
    $near: {
      $geometry: {
        type: "Point",
        coordinates: [ -73.98, 40.77 ]
      },
      $maxDistance: 1000
    }
  }
})

Geospatial Query Examples

Polygonal Area Query

Find all points within a specified polygon:

db.places.find({
  location: {
    $geoWithin: {
      $geometry: {
        type: "Polygon",
        coordinates: [[
          [ -73.98, 40.76 ],
          [ -73.99, 40.76 ],
          [ -73.99, 40.77 ],
          [ -73.98, 40.77 ],
          [ -73.98, 40.76 ]
        ]]
      }
    }
  }
})

Line-Polygon Intersection Query

Find all polygons that intersect with a specified line:

db.roads.find({
  geometry: {
    $geoIntersects: {
      $geometry: {
        type: "LineString",
        coordinates: [
          [ -73.98, 40.77 ],
          [ -73.99, 40.77 ]
        ]
      }
    }
  }
})

Index Selection and Optimization

Choosing between a 2d or 2dsphere index depends on the data type and use case:

  • If the data consists of simple two-dimensional planar coordinates and does not require consideration of the Earth's curvature, use a 2d index
  • If the data is in GeoJSON format or requires precise distance calculations on the Earth's surface, use a 2dsphere index

Example of a compound index:

db.places.createIndex({
  location: "2dsphere",
  category: 1,
  rating: -1
})

This compound index can optimize queries that include both geospatial conditions and other criteria.

Performance Considerations

The performance of geospatial indexes is influenced by the following factors:

  1. Data volume: The size of the index directly affects query performance
  2. Query complexity: $geoWithin is generally faster than $near
  3. Index type: 2d indexes are usually faster than 2dsphere indexes but have limited functionality

For large datasets, consider:

  • Using a sharded cluster to distribute geospatial data
  • Setting a reasonable $maxDistance to limit the result set size
  • Avoiding overly complex geometric shapes in queries

Practical Application Scenarios

Nearby Location Search

Implement a function to find nearby restaurants:

function findNearbyRestaurants(longitude, latitude, maxDistance) {
  return db.restaurants.find({
    location: {
      $nearSphere: {
        $geometry: {
          type: "Point",
          coordinates: [ longitude, latitude ]
        },
        $maxDistance: maxDistance
      }
    },
    category: "restaurant"
  }).sort({ rating: -1 }).limit(10)
}

Geofencing Application

Check if a user has entered a predefined area:

function checkGeoFence(userLocation, fenceId) {
  const fence = db.geoFences.findOne({ _id: fenceId })
  return db.geoFences.findOne({
    _id: fenceId,
    geometry: {
      $geoIntersects: {
        $geometry: {
          type: "Point",
          coordinates: userLocation
        }
      }
    }
  }) !== null
}

Geospatial Aggregation

MongoDB's geospatial aggregation capabilities can be used for more complex analyses:

Count the number of points in each region:

db.places.aggregate([
  {
    $geoNear: {
      near: { type: "Point", coordinates: [ -73.98, 40.77 ] },
      distanceField: "distance",
      maxDistance: 5000,
      spherical: true
    }
  },
  {
    $group: {
      _id: "$category",
      count: { $sum: 1 },
      avgDistance: { $avg: "$distance" }
    }
  }
])

Common Issues and Solutions

  1. Coordinate order issues:

    • GeoJSON uses [longitude, latitude] order
    • Traditional coordinates may use [latitude, longitude] order
    • Ensure consistent data formatting
  2. Performance optimization:

    • For large-range queries, first use $geoWithin to narrow the scope, then sort with $near
    • Avoid combining multiple geospatial conditions with the $or operator in queries
  3. Precision issues:

    • 2d indexes use planar distance calculations and are not suitable for large-scale geographic data
    • 2dsphere indexes use spherical distance calculations, offering higher precision but at greater computational cost

Advanced Usage

Combining Geospatial Data with Full-Text Search

db.places.createIndex({ location: "2dsphere", name: "text" })

db.places.find({
  $text: { $search: "coffee" },
  location: {
    $near: {
      $geometry: {
        type: "Point",
        coordinates: [ -73.98, 40.77 ]
      },
      $maxDistance: 1000
    }
  }
})

Dynamic Geospatial Queries

Build dynamic query conditions:

function buildGeoQuery(center, radius, categories) {
  const query = {
    location: {
      $geoWithin: {
        $centerSphere: [ center, radius / 6378.1 ]
      }
    }
  }
  
  if (categories && categories.length > 0) {
    query.category = { $in: categories }
  }
  
  return query
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.