go+MongoDB实现附近的人
在O2O与社交场景中,搜索附近的人、附近的商家是很常见的场景。那么我们如何实现呢?
接触的方法有:
- 坐标+球体距离计算公式
- 基于Redis的geo
- 基于MongoDB的geohash
前面的demo已经有接触Redis,这里我们就用mongoDB来实现一下。
我们就直接使用官方的实现好了:
go.mongodb.org/mongo-driver/mongo
连接
opt := options.Client().ApplyURI("mongodb://root:211111@localhost:27017")
// Connect to MongoDB
client, err := mongo.Connect(context.TODO(), opt)
if err != nil {
log.Fatal(err)
}
// Check the connection
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
我们可以设置更多:
opt.SetLocalThreshold(3 * time.Second) //只使用与mongo操作耗时小于3秒的
opt.SetMaxConnIdleTime(5 * time.Second) //指定连接可以保持空闲的最大毫秒数
opt.SetMaxPoolSize(200) //使用最大的连接数
opt.SetReadConcern(readconcern.Majority()) //指定查询应返回实例的最新数据确认为,已写入副本集中的大多数成员
model
// 坐标
type Location struct {
Type string `json:"type" bson:"type"`
Coordinates []float64 `json:"coordinates" bson:"coordinates"`
}
// 每个点
type Point struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city"`
Location Location `json:"location"`
}
数据写入
我们可以先插入数据
func(mgo *mgo) Start() {
collection := mgo.client.Database(DBName).Collection(CollectionName)
// 设置索引 2dsphere, 很重要
collection.Indexes().CreateOne(context.TODO(), mongo.IndexModel{
Keys: bson.M{Key: "2dsphere"},
})
a := Point{"王二", 18, "杭州", Location{"Point", []float64{120.185614,30.300738}}}
b := Point{"张三", 25, "杭州", Location{"Point", []float64{120.094778,30.310217}}}
c := Point{"小晴", 35, "绍兴", Location{"Point", []float64{120.603847,30.054237}}}
d := Point{"李四", 34, "杭州", Location{"Point", []float64{120.110893,30.207849}}}
e := Point{"小明", 24, "北京", Location{"Point", []float64{116.435721,39.914031}}}
f := Point{"吴六", 25, "杭州", Location{"Point", []float64{120.126443,30.33084}}}
h := Point{"于一", 23, "杭州", Location{"Point", []float64{120.28132,30.184083}}}
j := Point{"小七", 14, "杭州", Location{"Point", []float64{119.73926,30.247639}}}
// 单条插入
insertResult, err := collection.InsertOne(context.TODO(), a)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted a single document: ", insertResult.InsertedID)
ps := []interface{}{b, c, d, e, f, h, j}
// 批量插入
insertManyResult, err := collection.InsertMany(context.TODO(), ps)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted multiple documents: ", insertManyResult.InsertedIDs)
}
注意,设置索引 2dsphere, 很重要!!!
存储的数据格式
我们查找:
func (mgo *mgo) Near() {
collection := mgo.client.Database(DBName).Collection(CollectionName)
// 查找120.110893,30.2078490坐标附近15000米的人
cur, err := collection.Find(context.TODO(), bson.D{
{Key, bson.D{
{"$near", bson.D{
{
"$geometry", Location{
"Point",
[]float64{120.110893,30.2078490},
},
},
{"$maxDistance", 15000}, // 单位米
}},
}},
})
if err != nil {
fmt.Println(err)
return
}
var results []Point
for cur.Next(context.TODO()) {
var elem Point
err := cur.Decode(&elem)
fmt.Println(elem)
fmt.Println(cur)
if err != nil {
fmt.Println("Could not decode Point")
return
}
results = append(results, elem)
}
fmt.Println("查找到", len(results))
}
我们不妨运行一下:
能成功查找出了附近的人。
那么,如何计算距离呢?
可以经纬度计算,也可以直接mongoDB聚合查询,可以自行思索,参考代码点击见github。
go+MongoDB实现附近的人
https://blog.puresai.com/2021/02/12/goexample10/