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

MongoDB - Perpotongan geospasial dari dua poligon

Jadi melihat ini dengan pikiran segar, jawabannya adalah menatap wajah saya. Hal utama yang telah Anda nyatakan adalah Anda ingin menemukan "persimpangan" dari dua kueri dalam satu respons.

Cara lain untuk melihat ini adalah Anda ingin semua titik yang terikat oleh kueri pertama kemudian menjadi "input" untuk kueri kedua, dan seterusnya sesuai kebutuhan. Pada dasarnya itulah yang dilakukan persimpangan, tetapi logikanya sebenarnya literal.

Jadi cukup gunakan kerangka kerja agregasi untuk menghubungkan kueri yang cocok. Sebagai contoh sederhana, perhatikan dokumen berikut:

{ "loc" : { "type" : "Point", "coordinates" : [ 4, 4 ] } }
{ "loc" : { "type" : "Point", "coordinates" : [ 8, 8 ] } }
{ "loc" : { "type" : "Point", "coordinates" : [ 12, 12 ] } }

Dan saluran agregasi berantai, hanya dua kueri:

db.geotest.aggregate([
    { "$match": {
        "loc": {
            "$geoWithin": {
                "$box": [ [0,0], [10,10] ]
            }
        }
    }},
    { "$match": {
        "loc": {
            "$geoWithin": {
                "$box": [ [5,5], [20,20] ]
            }
        }
    }}
])

Jadi jika Anda mempertimbangkannya secara logis, hasil pertama akan menemukan titik-titik yang termasuk dalam batas kotak awal atau dua item pertama. Hasil tersebut kemudian ditindaklanjuti oleh kueri kedua, dan karena batas kotak baru dimulai dari [5,5] yang mengecualikan poin pertama. Poin ketiga sudah dikecualikan, tetapi jika batasan kotak dibalik maka hasilnya akan menjadi dokumen tengah yang sama saja.

Cara kerjanya cukup unik untuk $geoWithin operator kueri dibandingkan dengan berbagai fungsi geografis lainnya:

Jadi hasilnya baik dan buruk. Baik karena Anda dapat melakukan jenis operasi ini tanpa indeks di tempat, tetapi buruk karena setelah pipa agregasi mengubah hasil pengumpulan setelah operasi kueri pertama, tidak ada indeks lebih lanjut yang dapat digunakan. Jadi, semua manfaat kinerja indeks hilang saat menggabungkan hasil "set" dari apa pun setelah Polygon/MultiPolygon awal sebagaimana didukung.

Untuk alasan ini saya masih menyarankan Anda menghitung batas persimpangan "di luar" dari kueri yang dikeluarkan untuk MongoDB. Meskipun kerangka kerja agregasi dapat melakukan ini karena sifat pipa yang "terrantai", dan meskipun persimpangan yang dihasilkan akan semakin kecil, kinerja terbaik Anda adalah kueri tunggal dengan batas yang benar yang dapat menggunakan semua manfaat indeks.

Ada berbagai metode untuk melakukan itu, tetapi untuk referensi di sini adalah implementasi menggunakan JSTS library, yang merupakan port JavaScript dari JTS yang populer perpustakaan untuk Jawa. Mungkin ada port lain atau port bahasa lain, tetapi ini memiliki penguraian GeoJSON sederhana dan metode bawaan untuk hal-hal seperti mendapatkan batas persimpangan:

var async = require('async');
    util = require('util'),
    jsts = require('jsts'),
    mongo = require('mongodb'),
    MongoClient = mongo.MongoClient;

var parser = new jsts.io.GeoJSONParser();

var polys= [
  {
    type: 'Polygon',
    coordinates: [[
      [ 0, 0 ], [ 0, 10 ], [ 10, 10 ], [ 10, 0 ], [ 0, 0 ]
    ]]
  },
  {
    type: 'Polygon',
    coordinates: [[
      [ 5, 5 ], [ 5, 20 ], [ 20, 20 ], [ 20, 5 ], [ 5, 5 ]
    ]]
  }
];

var points = [
  { type: 'Point', coordinates: [ 4, 4 ]  },
  { type: 'Point', coordinates: [ 8, 8 ]  },
  { type: 'Point', coordinates: [ 12, 12 ] }
];

MongoClient.connect('mongodb://localhost/test',function(err,db) {

  db.collection('geotest',function(err,geo) {

    if (err) throw err;

    async.series(
      [
        // Insert some data
        function(callback) {
          var bulk = geo.initializeOrderedBulkOp();
          bulk.find({}).remove();
          async.each(points,function(point,callback) {
            bulk.insert({ "loc": point });
            callback();
          },function(err) {
            bulk.execute(callback);
          });
        },

        // Run each version of the query
        function(callback) {
          async.parallel(
            [
              // Aggregation
              function(callback) {
                var pipeline = [];
                polys.forEach(function(poly) {
                  pipeline.push({
                    "$match": {
                      "loc": {
                        "$geoWithin": {
                          "$geometry": poly
                        }
                      }
                    }
                  });
                });

                geo.aggregate(pipeline,callback);
              },

              // Using external set resolution
              function(callback) {
                var geos = polys.map(function(poly) {
                  return parser.read( poly );
                });

                var bounds = geos[0];

                for ( var x=1; x<geos.length; x++ ) {
                  bounds = bounds.intersection( geos[x] );
                }

                var coords = parser.write( bounds );

                geo.find({
                  "loc": {
                    "$geoWithin": {
                      "$geometry": coords
                    }
                  }
                }).toArray(callback);
              }
            ],
            callback
          );
        }
      ],
      function(err,results) {
        if (err) throw err;
        console.log(
          util.inspect( results.slice(-1), false, 12, true ) );
        db.close();
      }
    );

  });

});

Menggunakan representasi "Polygon" GeoJSON lengkap di sana karena ini diterjemahkan menjadi apa yang dapat dipahami dan dikerjakan oleh JTS. Kemungkinan masukan apa pun yang mungkin Anda terima untuk aplikasi nyata akan berada dalam format ini juga daripada menerapkan kenyamanan seperti $box .

Jadi itu bisa dilakukan dengan kerangka kerja agregasi, atau bahkan kueri paralel yang menggabungkan "kumpulan" hasil. Namun, meskipun kerangka kerja agregasi dapat melakukannya lebih baik daripada menggabungkan kumpulan hasil secara eksternal, hasil terbaik akan selalu datang dari menghitung batas terlebih dahulu.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Ulangi kursor Mongodb dari agregat

  2. Tidak dapat terhubung ke pod Mongodb di Kubernetes (Koneksi ditolak)

  3. Bagaimana mengatasi kesalahan SQLdecode saat Anda memigrasi model di Django?

  4. Django - MongoDB:(tidak dapat terhubung ke localhost:27017) Koneksi ditolak

  5. Kesalahan basis data MongoDB:basis data menghilang