Truy vấn không gian địa lý MongoDB: Xây dựng tính năng tìm nhà hàng gần đó với Robo 3T

Truy vấn không gian địa lý là một trong những tính năng mạnh mẽ của MongoDB, cho phép truy xuất dữ liệu dựa trên vị trí địa lý một cách hiệu quả. Bài viết này sẽ hướng dẫn bạn cách sử dụng Robo 3T - một công cụ quản lý MongoDB đa nền tảng - để xây dựng tính năng tìm kiếm nhà hàng trong khu vực lân cận, bao gồm việc thiết kế mô hình dữ liệu, tạo chỉ mục và tối ưu hóa truy vấn.

Thiết kế mô hình dữ liệu: Lưu trữ thông tin vị trí nhà hàng

MongoDB hỗ trợ định dạng GeoJSON để lưu trữ dữ liệu địa lý, với nhiều loại hình học như điểm, đường và vùng. Đối với việc lưu trữ vị trí nhà hàng, chúng ta cần thêm trường location chứa tọa độ longitude và latitude vào document.

Cấu trúc dữ liệu cơ bản

{
  "name": "Nhà hàng Bình Minh",
  "cuisine": "Việt Nam",
  "location": {
    "type": "Point",
    "coordinates": [106.629652, 10.823099]
  },
  "address": "Quận 1, TP. Hồ Chí Minh",
  "rating": 4.5
}

Lưu ý: Thứ tự tọa độ tuân theo chuẩn GeoJSON với kinh độ (longitude) trước, vĩ độ (latitude) sau, ngược với thói quen thông thường.

Thiết lập quy tắc xác thực dữ liệu

Thông qua chức năng quản lý collection của Robo 3T, có thể thiết lập các quy tắc xác thực dữ liệu địa lý để đảm bảo tính hợp lệ của tọa độ:

db.createCollection("danh_sach_nha_hang", {
  validator: {
    $jsonSchema: {
      required: ["location"],
      properties: {
        location: {
          bsonType: "object",
          required: ["type", "coordinates"],
          properties: {
            type: {
              enum: ["Point"]
            },
            coordinates: {
              bsonType: "array",
              minItems: 2,
              maxItems: 2,
              items: {
                bsonType: "number",
                minimum: -180,
                maximum: 180
              }
            }
          }
        }
      }
    }
  }
})

Tạo chỉ mục không gian địa lý

Để thực hiện truy vấn vị trí hiệu quả, cần tạo chỉ mục 2dsphere. Robo 3T cung cấp giao diện quản lý chỉ mục trực quan thông qua tùy chọn "Indexes" trong menu chuột phải collection.

Quy trình tạo chỉ mục

  1. Trong thanh điều hướng bên trái, mở rộng cơ sở dữ liệu mong muốn, nhấp chuột phải vào collection danh_sach_nha_hang
  2. Chọn "Indexes" → "Create Index"
  3. Nhập trường chỉ mục: { location: "2dsphere" }
  4. Đặt tên cho chỉ mục (ví dụ: idx_vi_tri) và xác nhận

Lệnh tạo chỉ mục

Cũng có thể thực hiện trực tiếp qua giao diện Shell của Robo 3T:

db.danh_sach_nha_hang.createIndex(
  { location: "2dsphere" },
  { name: "idx_vi_tri" }
)

Xây dựng tính năng tìm nhà hàng lân cận

Công cụ xây dựng aggregation pipeline của Robo 3T cung cấp giao diện cấu hình truy vấn không gian địa lý trực quan trong tab "Aggregation". Thông qua các thao tác可视化, có thể tạo giai đoạn pipeline $geoNear để thực hiện truy vấn vị trí với sắp xếp theo khoảng cách.

Truy vấn tìm kiếm cơ bản

Truy vấn sau sẽ trả về các nhà hàng trong phạm vi 5km từ vị trí hiện tại (Quận 1, TP. Hồ Chí Minh: 106.629652, 10.823099):

db.danh_sach_nha_hang.aggregate([
  {
    $geoNear: {
      near: {
        type: "Point",
        coordinates: [106.629652, 10.823099]
      },
      distanceField: "khoang_cach",
      maxDistance: 5000,
      spherical: true
    }
  },
  {
    $sort: { khoang_cach: 1 }
  },
  {
    $project: {
      name: 1,
      cuisine: 1,
      khoang_cach_km: { $divide: ["$khoang_cach", 1000] },
      rating: 1,
      location: 1
    }
  }
])

Xây dựng truy vấn trực quan

Trình chỉnh sửa aggregation pipeline của Robo 3T hỗ trợ kéo thả để thêm giai đoạn $geoNear và cung cấp biểu mẫu nhập tham số.

Truy vấn nâng cao: Kết hợp điều kiện kinh doanh

Trong thực tế, thường cần kết hợp nhiều điều kiện như khoảng cách, đánh giá, loại món ăn. Ví dụ dưới đây tìm các nhà hàng trong phạm vi 3km có đánh giá trên 4.5 và phục vụ món ăn Trung Hoa:

db.danh_sach_nha_hang.find({
  location: {
    $nearSphere: {
      $geometry: {
        type: "Point",
        coordinates: [106.629652, 10.823099]
      },
      $maxDistance: 3000
    }
  },
  cuisine: "Trung Hoa",
  rating: { $gte: 4.5 }
}).sort({ rating: -1 })

Tối ưu hóa hiệu suất và thực hành tốt

Tối ưu hóa chỉ mục

  • Chiến lược chỉ mục kết hợp: Kết hợp trường vị trí với các trường lọc thường dùng như { location: "2dsphere", cuisine: 1, rating: -1 }
  • Đánh giá tính chọn lọc của chỉ mục: Sử dụng db.danh_sach_nha_hang.getIndexes() để kiểm tra tình trạng sử dụng chỉ mục
  • Bảo trì chỉ mục: Thực hiện định kỳ db.danh_sach_nha_hang.reIndex() để tối ưu hóa chỉ mục bị phân mảnh

Giám sát hiệu suất truy vấn

Trong tab "Performance" của Robo 3T có thể giám sát quá trình thực thi truy vấn, tập trung vào:

  • executionTimeMillis: Thời gian thực thi truy vấn
  • totalDocsExamined vs totalKeysExamined: Tỷ lệ số document quét và số khóa chỉ mục quét
  • winningPlan: Xác nhận truy vấn sử dụng chỉ mục không gian địa lý như mong đợi

Chiến lược sharding dữ liệu

Khi lượng dữ liệu nhà hàng vượt quá hàng chục triệu, có thể thực hiện sharding theo khu vực địa lý:

sh.shardCollection("food.danh_sach_nha_hang", { location: "2dsphere" })

Tổng kết và ứng dụng mở rộng

Các bước cốt lõi để xây dựng tính năng tìm nhà hàng gần đó với Robo 3T bao gồm:

  1. Sử dụng định dạng GeoJSON để lưu trữ dữ liệu vị trí
  2. Tạo chỉ mục 2dsphere không gian địa lý
  3. Thực hiện truy vấn vị trí thông qua $geoNear hoặc $nearSphere
  4. Kết hợp chỉ mục kết hợp và phân tích truy vấn để tối ưu hiệu suất

Giải pháp này có thể mở rộng sang nhiều kịch bản dịch vụ vị trí khác như:

  • Tìm kiếm điểm đỗ xe xe共享单车
  • Tính toán phạm vi giao hàng cho đơn hàng ngoại tuyến
  • Phân tích mật độ dân cư theo khu vực

Thẻ: MongoDB geospatial robo3t 2dsphere geonear

Đăng vào ngày 7 tháng 6 lúc 19:41