MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Dukungan Geospasial di MongoDB

1. Ikhtisar

Dalam tutorial ini, kita akan menjelajahi dukungan Geospasial di MongoDB.

Kami akan membahas cara menyimpan data geospasial, pengindeksan geo, dan pencarian geospasial. Kami juga akan menggunakan beberapa kueri penelusuran geospasial seperti dekat , geoDalam , dan geoIntersects .

2. Menyimpan Data Geospasial

Pertama, mari kita lihat cara menyimpan data geospasial di MongoDB.

MongoDB mendukung banyak GeoJSON jenis untuk menyimpan data geospasial. Sepanjang contoh kami, kami terutama akan menggunakan Titik dan Poligon jenis.

2.1. Titik

Ini adalah GeoJSON yang paling dasar dan umum ketik, dan digunakan untuk mewakili satu titik tertentu pada petak .

Di sini, kami memiliki objek sederhana, di tempat kami koleksi, yang memiliki bidang lokasi sebagai Titik :

{
  "name": "Big Ben",
  "location": {
    "coordinates": [-0.1268194, 51.5007292],
    "type": "Point"
  }
}

Perhatikan bahwa nilai bujur didahulukan, kemudian garis lintang.

2.2. Poligon

Poligon sedikit lebih rumit GeoJSON ketik.

Kita bisa menggunakan Poligon untuk menentukan area dengan batas luarnya dan juga lubang interior jika diperlukan.

Mari kita lihat objek lain yang lokasinya didefinisikan sebagai Poligon :

{
  "name": "Hyde Park",
  "location": {
    "coordinates": [
      [
        [-0.159381, 51.513126],
        [-0.189615, 51.509928],
        [-0.187373, 51.502442],
        [-0.153019, 51.503464],
        [-0.159381, 51.513126]
      ]
    ],
    "type": "Polygon"
  }
}

Dalam contoh ini, kami mendefinisikan array titik yang mewakili batas luar. Kita juga harus menutup batas sehingga titik terakhir sama dengan titik pertama.

Perhatikan bahwa kita perlu mendefinisikan titik batas luar berlawanan arah jarum jam dan batas lubang searah jarum jam.

Selain tipe tersebut, masih banyak tipe lain seperti LineString, MultiPoint, MultiPoligon, MultiLineString, dan GeometryCollection.

3. Pengindeksan Geospasial

Untuk melakukan kueri penelusuran pada data geospasial yang kami simpan, kami perlu membuat indeks geospasial di lokasi kami lapangan.

Kami pada dasarnya memiliki dua opsi:2d dan 2dsphere .

Tapi pertama-tama, mari kita tentukan tempat kitakoleksi :

MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("myMongoDb");
collection = db.getCollection("places");

3.1. 2d Indeks Geospasial

2d index memungkinkan kami melakukan kueri penelusuran yang bekerja berdasarkan perhitungan bidang 2d.

Kita dapat membuat 2d indeks di lokasi di aplikasi Java kami sebagai berikut:

collection.createIndex(Indexes.geo2d("location"));

Tentu saja, kita dapat melakukan hal yang sama di mongo cangkang:

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

3.2. 2dsphere Indeks Geospasial

2dsphere index mendukung kueri yang bekerja berdasarkan perhitungan bola.

Demikian pula, kita dapat membuat 2dsphere indeks di Java menggunakan Indeks yang sama kelas seperti di atas:

collection.createIndex(Indexes.geo2dsphere("location"));

Atau di mongo cangkang:

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

4. Menelusuri Menggunakan Kueri Geospasial

Sekarang, untuk bagian yang menarik, mari kita cari objek berdasarkan lokasinya menggunakan kueri geospasial.

4.1. Dekat Kueri

Mari kita mulai dengan dekat. Kita dapat menggunakan dekat kueri untuk menelusuri tempat dalam jarak tertentu.

di dekat kueri berfungsi dengan keduanya 2d dan 2dsphere indeks.

Pada contoh berikutnya, kita akan mencari tempat yang berjarak kurang dari 1 km dan lebih dari 10 meter dari posisi yang diberikan:

@Test
public void givenNearbyLocation_whenSearchNearby_thenFound() {
    Point currentLoc = new Point(new Position(-0.126821, 51.495885));
 
    FindIterable<Document> result = collection.find(
      Filters.near("location", currentLoc, 1000.0, 10.0));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Dan kueri yang sesuai di mongo cangkang:

db.places.find({
  location: {
    $near: {
      $geometry: {
        type: "Point",
        coordinates: [-0.126821, 51.495885]
      },
      $maxDistance: 1000,
      $minDistance: 10
    }
  }
})

Perhatikan bahwa hasil diurutkan dari yang terdekat hingga terjauh.

Demikian pula, jika kita menggunakan lokasi yang sangat jauh, kita tidak akan menemukan tempat terdekat:

@Test
public void givenFarLocation_whenSearchNearby_thenNotFound() {
    Point currentLoc = new Point(new Position(-0.5243333, 51.4700223));
 
    FindIterable<Document> result = collection.find(
      Filters.near("location", currentLoc, 5000.0, 10.0));

    assertNull(result.first());
}

Kami juga memiliki nearSphere metode, yang bertindak persis seperti dekat, kecuali ia menghitung jarak menggunakan geometri bola.

4.2. Dalam Kueri

Selanjutnya, kita akan menjelajahi geoWithin kueri.

The geoWithin kueri memungkinkan kami menelusuri tempat yang sepenuhnya ada dalam Geometri . tertentu , seperti lingkaran, kotak, atau poligon. Ini juga berfungsi dengan keduanya 2d dan 2dsphere indeks.

Dalam contoh ini, kami mencari tempat yang ada dalam radius 5 km dari posisi tengah yang diberikan:

@Test
public void givenNearbyLocation_whenSearchWithinCircleSphere_thenFound() {
    double distanceInRad = 5.0 / 6371;
 
    FindIterable<Document> result = collection.find(
      Filters.geoWithinCenterSphere("location", -0.1435083, 51.4990956, distanceInRad));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Perhatikan bahwa kita perlu mengubah jarak dari km ke radian (cukup bagi dengan jari-jari Bumi).

Dan kueri yang dihasilkan:

db.places.find({
  location: {
    $geoWithin: {
      $centerSphere: [
        [-0.1435083, 51.4990956],
        0.0007848061528802386
      ]
    }
  }
})

Selanjutnya, kita akan mencari semua tempat yang ada di dalam "kotak" persegi panjang. Kita perlu mendefinisikan kotak dengan posisi kiri bawah dan posisi kanan atas:

@Test
public void givenNearbyLocation_whenSearchWithinBox_thenFound() {
    double lowerLeftX = -0.1427638;
    double lowerLeftY = 51.4991288;
    double upperRightX = -0.1256209;
    double upperRightY = 51.5030272;

    FindIterable<Document> result = collection.find(
      Filters.geoWithinBox("location", lowerLeftX, lowerLeftY, upperRightX, upperRightY));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Inilah kueri yang sesuai di mongo cangkang:

db.places.find({
  location: {
    $geoWithin: {
      $box: [
        [-0.1427638, 51.4991288],
        [-0.1256209, 51.5030272]
      ]
    }
  }
})

Terakhir, jika area yang ingin kita telusuri bukan persegi panjang atau lingkaran, kita dapat menggunakan poligon untuk mendefinisikan area yang lebih spesifik :

@Test
public void givenNearbyLocation_whenSearchWithinPolygon_thenFound() {
    ArrayList<List<Double>> points = new ArrayList<List<Double>>();
    points.add(Arrays.asList(-0.1439, 51.4952));
    points.add(Arrays.asList(-0.1121, 51.4989));
    points.add(Arrays.asList(-0.13, 51.5163));
    points.add(Arrays.asList(-0.1439, 51.4952));
 
    FindIterable<Document> result = collection.find(
      Filters.geoWithinPolygon("location", points));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Dan inilah kueri yang sesuai:

db.places.find({
  location: {
    $geoWithin: {
      $polygon: [
        [-0.1439, 51.4952],
        [-0.1121, 51.4989],
        [-0.13, 51.5163],
        [-0.1439, 51.4952]
      ]
    }
  }
})

Kami hanya mendefinisikan poligon dengan batas luarnya, tetapi kami juga dapat menambahkan lubang padanya. Setiap lubang akan menjadi Daftar dari Titik s:

geoWithinPolygon("location", points, hole1, hole2, ...)

4.3. Kueri Perpotongan

Terakhir, mari kita lihat geoIntersects kueri.

The geoIntersects query menemukan objek yang setidaknya berpotongan dengan Geometri. given Sebagai perbandingan, geoWithin menemukan objek yang sepenuhnya ada dalam Geometri yang diberikan .

Kueri ini berfungsi dengan 2dsphere indeks saja.

Mari kita lihat ini dalam praktik, dengan contoh mencari tempat mana pun yang berpotongan dengan Poligon :

@Test
public void givenNearbyLocation_whenSearchUsingIntersect_thenFound() {
    ArrayList<Position> positions = new ArrayList<Position>();
    positions.add(new Position(-0.1439, 51.4952));
    positions.add(new Position(-0.1346, 51.4978));
    positions.add(new Position(-0.2177, 51.5135));
    positions.add(new Position(-0.1439, 51.4952));
    Polygon geometry = new Polygon(positions);
 
    FindIterable<Document> result = collection.find(
      Filters.geoIntersects("location", geometry));

    assertNotNull(result.first());
    assertEquals("Hyde Park", result.first().get("name"));
}

Kueri yang dihasilkan:

db.places.find({
  location:{
    $geoIntersects:{
      $geometry:{
        type:"Polygon",
          coordinates:[
          [
            [-0.1439, 51.4952],
            [-0.1346, 51.4978],
            [-0.2177, 51.5135],
            [-0.1439, 51.4952]
          ]
        ]
      }
    }
  }
})

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mendefinisikan skema Mongoose on-the-fly dari 'deskripsi' berformat JSON

  2. Apa yang Baru di MongoDB 4.4

  3. Pertimbangan Dasar untuk Mengambil Cadangan MongoDB

  4. hitung kemunculan array di semua dokumen dengan mongo

  5. Masalah MongoDB PHP UTF-8