ذخیره‌ی محیط جغرافیایی برای بررسی نقاط

Save the Geographical Environment to Check Points

25 اردیبهشت 1401
درسنامه درس 65 از سری دوره جامع آموزش MongoDB
MongoDB: ذخیره ی محیط جغرافیایی برای بررسی نقاط (قسمت 67)

ما در جلسه قبل به این موضوع پرداختیم که آیا نقاط ذخیره شده در پایگاه داده در یک محیط جغرافیایی خاص هستند یا خیر. در این جلسه می خواهیم برعکس این موضوع را بررسی کنیم؛ یعنی محیط های جغرافیایی خاصی را در پایگاه داده ذخیره کنیم و ببینیم آیا یک نقطه خاص در آن محیط ها وجود دارد یا خیر. در بسیاری از برنامه های واقعی به همین شکل از map ها استفاده می شود. مثلا کاربر مختصات خود را به شما می گوید و شما وجود او در یک منطقه یا شهر را بررسی می کنید.

برای این کار باید ابتدا چند ضلعی (Polygon) خود را درون پایگاه داده ذخیره کنیم. اگر یادتان رفته است، نقاط آن به شکل زیر بودند:

const p1 = [-122.4547, 37.77473]
const p2 = [-122.45303, 37.76641]
const p3 = [-122.51026, 37.76411]
const p4 = [-122.51088, 37.77131]

ما می توانیم با یک دستور ساده این ناحیه را درون پایگاه داده ذخیره کنیم:

db.areas.insertOne({name: "Golden Gate Park", area: {type: "Polygon", coordinates: [[p1, p2, p3, p4, p1]]}})

این کوئری، محیط پارک Golden Gate را درون یک کالکشن جدید به نام areas ذخیره می کند. همچنین همانطور که در جلسات قبل فیلد location یک نام دلخواه بود، فیلد area نیز کاملا به سلیقه شما بستگی دارد و می توانید هر مقداری را به جای آن قرار دهید. در جلسه قبل در مورد ساختار polygon ها صحبت کردیم بنابراین اگر یادتان رفته است به آن جلسه مراجعه کنید.

برای مطمئن شدن از اینکه متغیر های p1 تا p4 به درستی کار کرده اند باید یک بار داده ها را بخوانیم:

db.areas.findOne()

نتیجه:

"_id" : ObjectId("5ec0e1267bc8c6a2b7e4ab89"),
 "name" : "Golden Gate Park",                 
 "area" : {                                   
         "type" : "Polygon",                  
         "coordinates" : [                    
                 [                            
                         [                    
                                 -122.4547,   
                                 37.77473     
                         ],                   
                         [                    
                                 -122.45303,  
                                 37.76641     
                         ],                   
                         [                    
                                 -122.51026,  
                                 37.76411     
                         ],                   
                         [                    
                                 -122.51088,  
                                 37.77131     
                         ],                   
                         [                    
                                 -122.4547,   
                                 37.77473     
                         ]                    
                 ]                            
         ]                                    
 }                                            

حالا که تمام مختصات نمایش داده شده اند و نقطه اول با نقطه آخر یکی است (هر دو P1)، نتیجه می گیریم که متغیر ها به درستی کار کرده اند. اگر ترمینال را قبل از اجرای insertOne بسته باشید، متغیر ها نیز حذف می شوند و باید دوباره آن ها را تعریف کنید.

در مرحله بعد باید یک ایندکس geospatial بسازیم. اگر از جلسه قبل یادتان مانده باشد، برای کار با بسیاری از داده های geospatial وجود ایندکس ضروری است بنابراین:

db.areas.createIndex({area: "2dsphere"})

من یک نقطه تصادفی از درون پارک Golden Gate را انتخاب کرده ام و می خواهم ببینم آیا این نقطه درون پارک است یا نه (من خودم می دانم که نقطه درون پارک است اما می خواهم پاسخ کد ها را ببینم). برای این کار به یک کوئری ساده نیاز داریم:

db.areas.find({area: {$geoIntersects: {$geometry: {type: "Point", coordinates: [-122.49089, 37.76992]}}}}).pretty()

در اینجا ابتدا فیلد area را پاس داده ایم تا مشخص شود در چه فیلدی باید به دنبال محیط خود باشیم. سپس اپراتور geoIntersects$ را داریم. تفاوت این اپراتور با اپراتور geoWithing$ به صورت زیر است:

  • geoWithin$ به ما اجازه می داد که مشخص کنیم چه نقاطی درون یک محیط جغرافیایی هستند.
  • geoIntersects$ به ما اجازه می دهد که نقاطی را پیدا کنیم که مختصاتشان با هم تلاقی دارند.

بر اساس این دو نکته آیا فهمیدید که چرا از geoWithin$ استفاده نکرده ایم؟ ما نمی توانیم محیط هایی را پیدا کنیم که درون یک نقطه هستند! یک نقطه جغرافیایی نمی تواند درون خود چیزی داشته باشد (محیط نیست) بنابراین geoWithing معنی نمی دهد و باید به جای آن به دنبال محل تلاقی نقطه و محیط باشیم تا مشخص شود که نقطه ما درون آن محیط است یا خیر (اگر نقطه با محیط تلاقی داشته باشند قطعا در نقشه روی هم هستند). پس از آن اپراتور geometry$ را پاس داده ایم که همان GeoJSON ما است و type و coordinates دارد. مختصاتی که در کوئری بالا وارد کرده ام همان نقطه ای است که به دلخواه از روی نقشه انتخاب کرده بودم و شما می توانید هر مختصات دیگری را به جای آن قرار دهید.

نتیجه اجرای کوئری بالا به شکل زیر است:

"_id" : ObjectId("5ec0e1267bc8c6a2b7e4ab89"), 
 "name" : "Golden Gate Park",                  
 "area" : {                                    
         "type" : "Polygon",                   
         "coordinates" : [                     
                 [                             
                         [                     
                                 -122.4547,    
                                 37.77473      
                         ],                    
                         [                     
                                 -122.45303,   
                                 37.76641      
                         ],                    
                         [                     
                                 -122.51026,   
                                 37.76411      
                         ],                    
                         [                     
                                 -122.51088,   
                                 37.77131      
                         ],                    
                         [                     
                                 -122.4547,    
                                 37.77473      
                         ]                     
                 ]                             
         ]                                     
 }                                             

سند مربوط به پارک Golden Gate برگردانده شده است بنابراین نقطه ما با این محیط تلاقی دارد. البته ما فقط یک سند را در کالکشن خود داریم و اگر چندین سند را داشتیم و تمام این سند ها با کوئری بالا همخوانی داشت (نقطه درون همه آن ها بود)، همگی برگردانده می شدند. همچنین به یاد داشته باشید که می توانید به جای نقطه از یک محیط دیگر استفاده کنید تا ببینید آیا این دو محیط با هم تلاقی دارند یا خیر. مثلا یک محیط می شود پارک Golden Gate و محیط دیگر می شود یک محله خاص (مثلا محله ای که پارک Golden Gate در آن قرار دارد)، سپس بررسی می کنیم که آیا این پارک درون این محله قرار دارد یا خیر؟

حالا برای تست یک نقطه دیگر را انتخاب می کنیم که درون پارک Golden Gate نباشد. سپس می گوییم:

db.areas.find({area: {$geoIntersects: {$geometry: {type: "Point", coordinates: [-122.48446, 37.77776]}}}}).pretty()

مختصاتی که به این کوئری داده ام، یک نقطه تصادفی خارج از پارک Golden Gate است. با اجرای این کوئری هیچ نتیجه ای برای ما برگردانده نمی شود چرا که نقطه خارج از پارک بوده است.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش MongoDB توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
آخرین سوالات کاربران
5451218 در 4 سال قبل پرسیده:
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو