Search User Based on Latlong With Distance Golang Mongodb

Location based search in golang with mongodb#

If you are building api for any of the location based app then there must be scenario where you have to search users within certain radius using users current location.

so that can be done very easily with mongodb because mongodb have built in 2dsphere index which will handle the calculation part of latitude and longitude.

Suppose you have collection of users with structure like below

{
    "_id":"62efa58350aa6f9bd41f3eff",
    "first_name":"john",
    "last_name":"Doe",
    "email":"abc@exaple.com"

}

Now add one more property location which will store latitude and longitude of the users

location should have two sub proprty one is type and second is coordinates. type will be Point and coordinates will be array [longitude, latitude]. make sure that first value in coordinates is longitude.

user collection will look like this.

{
    "_id":"62efa58350aa6f9bd41f3eff",
    "first_name":"john",
    "last_name":"Doe",
    "email":"abc@exaple.com",
    "location": {
        "type": "Point",
        "coordinates": [-122.4545454,37.4354545],
    }

}

now add index on location field which will be of type 2dsphere.

Now i will create a Search function for searching users. this will be like below.

there should be only one child property in m mongo.Pipeline so if you want additional filters along with lat long you can add that into $geoNear > query property like service_category.#

search.go

package main

import (
	"context"
	"fmt"	
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)


const (
	UsersCollection = "users"
)

type Location struct {
	Type        string    `json:"type" bson:"type"`
	Coordinates []float64 `json:"coordinates" bson:"coordinates"`
}

type User struct {
    ID               string `json:"id" bson:"_id"`
    Firstname        string `json:"first_name" bson:"first_name"`
	Lastname         string `json:"last_name" bson:"last_name"`
    Email            string `json:"email" bson:"email"`
    Location       Location    `json:"location" bson:"location"`
}

func Search(latitude, longitude float64) ([]*User, error) {

    location := Location{
		"Point",
		[]float64{longitude, latitude},
	}
	

	filter :=
		bson.D{
			{"$geoNear",
				bson.D{
					{"near", location},
					{"maxDistance", 5000},
					{"spherical", true},
					{"distanceField", "distance"},
					{"distanceMultiplier", 1}, // this means distance field will be in meter
					{"query", bson.D{
						{"service_category", categoryId}, // Additional Filters
					}},
				},
			},
		}

	client := mongodb.NewMongo()
    defer client.CloseMongo()
    db := client.GetMongoDB()

	var result []*User

	cursor, err := db.Collection(UsersCollection).Aggregate(context.TODO(), mongo.Pipeline{filter})
	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}
	if err = cursor.All(context.TODO(), &result); err != nil {
		fmt.Println(err)
		return nil, err
	}
	defer cursor.Close(context.TODO())
	return result, nil

}

Connecting mongodb with golang#

for connectivity with mongodb database create a mongodb folder in root of the project and create mongo.go file with the following content

mongodb/mongo.go


package mongodb

import (
	"context"
	"fmt"
	"os"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
    "github.com/joho/godotenv"
)

func init() {
	err := godotenv.Load("../.env")
	if err != nil {
		log.Println(err.Error())
	}
}

type Mongodb struct {
	client *mongo.Client
}

var MongoClient *Mongodb



func NewMongo() *Mongodb {
	// uri := os.Getenv("MONGODB_URI")
	dbName := os.Getenv("DB_NAME")
	dbHost := os.Getenv("DB_HOST")
	dbUsername := os.Getenv("DB_USERNAME")
	dbPassword := os.Getenv("DB_PASSWORD")
	connectionString := fmt.Sprintf("mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority", dbUsername, dbPassword, dbHost, dbName)
	fmt.Println(connectionString)
	client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(connectionString))
	if err != nil {
		panic(err)
	}
	
	MongoClient = &Mongodb{
		client: client,
	}
	return MongoClient

}

func (m *Mongodb) GetMongoDB() *mongo.Database {

	dbName := os.Getenv("DB_NAME")
	return m.client.Database(dbName)
}

func (m *Mongodb) CloseMongo() {

	if err := m.client.Disconnect(context.TODO()); err != nil {
		panic(err)
	}

}





Do not forget to create .env file in root folder with all the database connection details. Now its time to use your Search() function in main file. This is how your main.go file will look like

main.go

package main

import (
    "fmt"
    "encoding/json"
)

func main() {
    latitude := 36.34343436
    longitude := -122.3234266654

    users, err := Search(latitude, longitude)
    if err != nil {
        fmt.Println(err)
        return
    }

    jsonString, err := json.Marshal(users)
    if err != nil  {
        fmt.Println(err)
        return
    }

    fmt.Println(string(jsonString))


}


I hope this is enough for you to get started working with mongodb and latlong search in golang, for any doubt you can comment or send me a mail so that i can help.

mailid - dheerajv4855@gmail.com

comments powered by Disqus