cover
MongoDBGeospatialGeoJSONADs

Avoiding Ad Overcrowding with Geospatial Indexes

Cover
geospatial.png
Slug
geospatial-indexes-mongodb
Published
Published
Date
Aug 4, 2024
Category
MongoDB
Geospatial
GeoJSON
ADs
Alright, folks, gather 'round. Let's talk about a little problem I solved while working on a project. Imagine a world where ads are like cockroaches—everywhere, creeping up next to each other, grossing everyone out. Our task? To make sure these pesky ads don’t end up on top of each other or within 3 meters like this.
notion image
How did we do it? With a dash of Mongoose magic and a sprinkle of geospatial indexing. We’re dealing with ads, and not the kind that you can skip after 5 seconds. No, these are the persistent kind, and they can’t be all over the same place. We need to make sure each ad is spaced out like introverts at a party. The challenge? Preventing any ad from being placed within 3 meters of another.

The Solution

Enter Mongoose, our trusty sidekick, armed with geospatial superpowers. By using Mongoose's support for GeoJSON objects and 2dsphere indexes, we can efficiently handle geospatial data and queries. Here's how I did it:

Schema Design

First, the schema. You know, the thing that defines the structure of our data. Here’s what it looks like:
import mongoose from "mongoose"; const Schema = mongoose.Schema; const adPostSchema = new Schema({ // other irrelevant stuff Latitude: Number, Longitude: Number, location: { type: { type: String, enum: ["Point"], required: true }, coordinates: { type: [Number], required: true }, }, }); adPostSchema.index({ location: "2dsphere" }); const AdPost = mongoose.model("AdPost", adPostSchema); export default AdPost;
Let me break it down for you:
  • location.type: This is always "Point". It’s not rocket science, just geometry.
  • location.coordinates: It’s a pair of numbers—longitude and latitude. Yes, the Earth is round.
  • 2dsphere index: This is where the magic happens. It tells MongoDB, "Hey, treat this like a globe." Because, guess what? The Earth isn’t flat, no matter what your conspiracy-theorist uncle says.

Geospatial Query Implementation

To prevent ad overcrowding, we crafted a query to check for existing ads within a 3-meter radius before adding a new one. Think of it as a digital bouncer, ensuring no ad gets too close for comfort:
const postAd = async (req, res) => { const { // other irrelevent stuff Latitude, Longitude, } = req.body; try { // Define the location in GeoJSON format const location = { type: "Point", coordinates: [Longitude, Latitude], }; // Check for existing ads within 3 meters (0.003 km) const existingAd = await AdPost.findOne({ location: { $near: { $geometry: location, $maxDistance: 3, // distance in meters }, }, }); if (existingAd) { return res.status(400).json({ message: "An ad already exists within 3 meters of this location." }); } // Proceed to save the ad if no conflicts are found } catch (error) { res.status(500).send("Error adding post: "); console.log(error); } };
Here's what happens:
  • We define the location using GeoJSON
  • We use the $near operator to find any ads within a 3-meter radius. If we find one, we block the new ad. Simple as that.

Conclusion

And that’s it. We managed to keep ads from piling up like trash on a New York street. Thanks to the 2dsphere index, we can efficiently and accurately manage ad placements without the headache. For those who want to dive deeper into the glorious details, check out Mongoose's GeoJSON documentation. Enjoy.