Jörgen Nilsson - MongoMunich 2011 MongoDB at Modondo Publify - A centralized decentralized CMS in the cloud... or space “MonkeyApp” - Project management specialized for web projects Modondo.com - Our own web site måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 ChitChat - Message system built as a mountable engine for Ruby on Rails Ett Bra Vin - A small wine project (ettbravin.se - Swedish only) The Daily List - A simple to-do browser application using hosted MongoDB services (MongoLab and MongoHQ) My personal web site, a never ending project Querycus - The handy document browser Labs and personal projects måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Query types and commands $near and $within are the two query types used with find() $near - Used for finding locations close and around a specific place (coordinate) $within - Used for finding locations within a bounding area geoNear - Similar to find() but returns distances and diagnostics for near queries which is good for calculations or debugging. måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Query types and commands $within $box - Search within a box based on SouthWest and NorthEast coordinates $center - Search from a specific point and within a certain radius $polygon - Search within a polygon shape, you could be brave and call it a freeform måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 The basics - Getting started Model your document Apply the index Populate your collection Make a search Make another search and celebrate with a beer Enjoy the fun :) måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Model your document A simple place document could look like this and it will also be used in the following examples { formatted_address: "", kind: "", location: {"lat": "", "lng": ""} } We have chosen to use descriptive keys instead of relying on the order in the array All examples can be run with db.places.find(); måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Model your document or like this... # MongoID - Ruby on Rails class Places include Mongoid::Document field :formatted_address, type: String field :kind, type: String field :location, type: Hash index [[ :location, Mongo::GEO2D ]], min: 180, max: 180 end måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Querying - Compound Geospatial Indexes If you are querying often on a location and other attributes at the same time, create a compound index Makes filtering faster db.places.ensureIndex( { location : "2d" , kind : 1 } ); måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Some points to remember Default limit of documents that is returned by a geo query is 100 documents. You should always limit the amount of documents to what you really need. Create index using ensureIndex and passing “2d” as value. Use unordered queries whenever possible The Earth is Round but Maps are Flat måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 More than just maps You can create and specify your own grid Can be used for various kind of games or in all places you need a grid and coordination system. Why not use it for a Dungeon and Dragons game? Or as Word2 - build a giant word game måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Use case - Service description Find your next holiday is a service where users can rent or exchange homes with each other. Users should be able to search the entire world for holiday homes and view them on a map. The use case description has been very simplified to better illustrate the design and solution. måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Use case - Background - Stats 40 000+ users world wide 40 000+ location objects 18 languages 4000+ visits a day 60 000+ page views per day måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Use case - Background - Tech stack Ubuntu server Ruby on Rails Ruby 1.9.2 Nginx + Phusion, (WEBrick for local dev) PostgresSQL MongoDB MongoID RVM måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Use case - Why MongoDB? No special datatype needed. Just store longitude and latitude as floats in array and apply the GEO2D index. Short and concise quires for finding items close by or within a bound in the form of rectangle, circle and polygon shape (geoNear and Bounds). Stored values are human readable and can be accessed and output into various contexts. måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Use case - Why MongoDB Works great with MongoID – An Ruby Object- Document-Mapper (ODM) No special configurations needed, it works right out of the box Great for keyword searches Easy to expand the data, no need to worry for NULL values måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Use case scenarios All of the following examples are based on the usage of Ruby on Rails together with MongoDB and MongoID. It also uses and relies heavily on Google Maps JavaScript API v3 måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 1 - Adding a property The user adds the property to the system by entering the property’s address in a input field By using Googles Places API we get a nice autocomplete and get the coordinates for the property and place a maker on the map The user can adjust the marker on the map and we get instant feedback on the coordinates The user clicks on the “save location” button and everything is stored down to MongoDB måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 1 - Adding a property The stored document looks like this so far class Place include Mongoid::Document include Mongoid::Timestamps field :user_id, type: Integer field :street, type: String field :postal_town, type: String field :postal_code, type: String field :country, type: String field :formatted_address, type: String field :location, type: Hash index [[ :location, Mongo::GEO2D ]], min: 180, max: 180 end måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 2 - Adding locations near our property Now when we have a property we can add places that is connected or are relevant to our property. The connected places are added to the property by adding markers to a Google map. Each connected location are embedded into our current document as surroundings and takes advantage of the Multi-Location feature available in version 2.0 of MongoDB måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 2 - Adding locations near our property The markers are for illustrative purposes and the locations are therefore not real and accurate. måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 2 - Adding locations near our property Our property document now looks like this class Place include Mongoid::Document include Mongoid::Timestamps field :user_id, type: Integer field :street, type: String field :postal_town, type: String field :postal_code, type: String field :country, type: String field :formatted_address, type: String field :location, type: Hash field embeds_many :surroundings index [[ :location, Mongo::GEO2D ]], min: 180, max: 180 end måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 2 - Adding locations near our property class surroundings include Mongoid::Document include Mongoid::Timestamps field :kind, type: String field :formatted_address, type: String field :location, type: Hash embedded_in :places index [[ :location, Mongo::GEO2D ]], min: 180, max: 180 end Our embedded document looks like this måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 3 - Searching for a property It is now super easy to find properties near or around Munich måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Scenario 4 - Looking at a property Nearly effortless we can list all interesting surroundings and use various filters to show and hide them måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 When searching for New Zealand you would get the following bounds coordinates back. South West Lat: -52.72, Lng: 165.74 North East Lat: -28.87, Lng: -175.06 Negative and positive latitude coordinates that overlaps Should I read that way or that way? Lessons learned - The kiwi issue måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Lessons learned - The kiwi issue You have to construct two boxes One that goes from 165.74 to 179.99 and one that goes from 180.00 to -175.06 You simply use an “or” statement applied by the following condition. If southwest longitude > north east longitude måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Lessons learned - Point not in range To narrow index, make sure the values are within the given range in the index. Default indexing values are -180, 180, which you could say corresponds to the earths bounds. Expand the index min and max values Check for incorrect values for the index Make sure there aren’t any spaces, tabs or other odd characters around the coordinates if importing data måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Lessons learned - Be consistent Use keys for latitude and longitude Automate as much as possible Don’t let users enter their own geo data Always validate your input values måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Lessons learned - Conventions Modondo are using the following format for storing geo coordinates. “location” : {“lat”: 51.5171003, “lng” : “-0.1406875999”} It is quite self explanatory, it is easer to read and understand both for clients and other developers that wasn’t around during the development It is the same “format” and order that Google Maps are using for their API måndag 17 oktober 11
Jörgen Nilsson - MongoMunich 2011 Resources There are not that much information or documentation about Geospatial indexing and what you can with it in MongoDB. Why? Maybe because it so easy? I’ve collected a few resources that I see as good starting points. Hope it helps. måndag 17 oktober 11