osm2mongo/main.go
Alexander NeonXP Kiryukhin a523b63679 fix indexes
2019-05-26 10:38:35 +03:00

192 lines
4.7 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"time"
"github.com/paulmach/osm"
"github.com/paulmach/osm/osmpbf"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/x/bsonx"
)
func main() {
dbconnection := flag.String("dbconnection", "mongodb://localhost:27017", "Mongo database name")
dbname := flag.String("dbname", "osm", "Mongo database name")
osmfile := flag.String("osmfile", "", "OSM file")
flag.Parse()
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
client, err := mongo.Connect(ctx, options.Client().ApplyURI(*dbconnection))
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(context.Background())
db := client.Database(*dbname)
if err := read(db, *osmfile); err != nil {
log.Fatal(err)
}
}
func read(db *mongo.Database, file string) error {
nodes := db.Collection("nodes")
_, _ = nodes.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"osm_id", bsonx.Int32(1)}},
Options: options.Index().SetUnique(true).SetSparse(true).SetBackground(true),
},
)
_, _ = nodes.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"coords", bsonx.Int32(1)}},
Options: options.Index().SetSphereVersion(2).SetSparse(true).SetBackground(true),
},
)
ways := db.Collection("ways")
_, _ = ways.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"osm_id", bsonx.Int32(1)}},
Options: options.Index().SetUnique(true).SetSparse(true).SetBackground(true),
},
)
_, _ = ways.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"nodes", bsonx.Int32(1)}},
Options: options.Index().SetSparse(true).SetBackground(true),
},
)
relations := db.Collection("relations")
_, _ = relations.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"osm_id", bsonx.Int32(1)}},
Options: options.Index().SetUnique(true).SetSparse(true).SetBackground(true),
},
)
_, _ = relations.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"members.ref", bsonx.Int32(1)}},
Options: options.Index().SetUnique(true).SetSparse(true).SetBackground(true),
},
)
_, _ = relations.Indexes().CreateOne(
context.Background(),
mongo.IndexModel{
Keys: bsonx.Doc{{"members.coords", bsonx.Int32(1)}},
Options: options.Index().SetSphereVersion(2).SetSparse(true).SetBackground(true),
},
)
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
opts := (new(options.ReplaceOptions)).SetUpsert(true)
nc := 0
wc := 0
rc := 0
scanner := osmpbf.New(context.Background(), f, 3)
defer scanner.Close()
for scanner.Scan() {
o := scanner.Object()
switch o := o.(type) {
case *osm.Way:
nodes := make([]int64, 0, len(o.Nodes))
for _, v := range o.Nodes {
nodes = append(nodes, int64(v.ID))
}
w := Way{
OsmID: int64(o.ID),
Tags: convertTags(o.Tags),
Nodes: nodes,
Timestamp: o.Timestamp,
Version: o.Version,
Visible: o.Visible,
}
if _, err = ways.ReplaceOne(context.Background(), bson.M{"osm_id": int64(o.ID)}, w, opts); err != nil {
return err
}
wc++
case *osm.Node:
n := Node{
OsmID: int64(o.ID),
Location: Coords{
Type: "Point",
Coordinates: []float64{
o.Lon,
o.Lat,
}},
Tags: convertTags(o.Tags),
Version: o.Version,
Timestamp: o.Timestamp,
Visible: o.Visible,
}
if _, err = nodes.ReplaceOne(context.Background(), bson.M{"osm_id": int64(o.ID)}, n, opts); err != nil {
return err
}
nc++
case *osm.Relation:
members := make([]Member, len(o.Members))
for _, v := range o.Members {
members = append(members, Member{
Type: v.Type,
Version: v.Version,
Orientation: v.Orientation,
Ref: v.Ref,
Role: v.Role,
Location: Coords{
Type: "Point",
Coordinates: []float64{
v.Lon,
v.Lat,
}},
})
}
r := Relation{
OsmID: int64(o.ID),
Tags: convertTags(o.Tags),
Version: o.Version,
Timestamp: o.Timestamp,
Visible: o.Visible,
Members: members,
}
if _, err = relations.ReplaceOne(context.Background(), bson.M{"osm_id": int64(o.ID)}, r, opts); err != nil {
return err
}
rc++
}
fmt.Printf("\rNodes: %d Ways: %d Relations: %d", nc, wc, rc)
}
scanErr := scanner.Err()
if scanErr != nil {
return scanErr
}
return nil
}
func convertTags(tags osm.Tags) map[string]string {
result := make(map[string]string, len(tags))
for _, t := range tags {
result[t.Key] = t.Value
}
return result
}