「MongoDBの Offical Go言語 Driverを使ってみる」の3回目の投稿Find編です
Find用のドキュメントのInsert
平成31年地価公示(東京都分) 公示価格個別地点データ(CSV)をダウンロード
次のURLからMongoDBにInsert用のCSVデータをダウンロードします。
地価公示データをMongoDBに登録
- ダウンロードしたデータはSJISなのでgolang.org/x/text/encoding/japaneseを使って文字コード変換します
- 英文字の項目名を考えるのが面倒なので日本語にする
- 項目名の先頭文字が大文字の英字でないとMongoDBにInsertされないので、Fを付けて、MongoDB上の項目名はタグに指定します
- MongoDBにInsertする項目は都道府県市区町村コードから地積までとします
- 価格などは数値項目ですが","が使われているので","を取り除く処理をしています
- InsertはUseSessionを使ってトランザクション処理としました
- insertDataのタイプは []地価公示としないこと
- Insert件数は2603件でした
insert.go
package main
import (
"context"
"encoding/csv"
"io"
"log"
"os"
"strconv"
"strings"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
)
type 地価公示 struct {
Fコード int "コード"
F対象年 int "対象年"
F標準地名 string "標準地名"
F標準地番号用途 int "標準地番号用途"
F標準地番号連番 int "標準地番号連番"
F区市町村名 string "区市町村名"
F地番 string "地番"
F住居表示 string "住居表示"
F当年価格 int "当年価格"
F前年価格 int "前年価格"
F変動率 float64 "変動率"
F地積 int "地積"
}
func toInt(data string) (int, error) {
intData := strings.Trim(strings.ReplaceAll(data, ",", ""), " ")
return strconv.Atoi(intData)
}
func toFloat(data string) (float64, error) {
floatData := strings.Trim(strings.ReplaceAll(data, ",", ""), " ")
return strconv.ParseFloat(floatData, 64)
}
func mainMain() error {
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
return err
}
if err = client.Connect(context.Background()); err != nil {
return err
}
defer client.Disconnect(context.Background())
col := client.Database("test").Collection("col")
csvFile, err := os.Open("./31kouji_chiten_data.csv")
if err != nil {
log.Fatal(err)
}
defer csvFile.Close()
reader := csv.NewReader(transform.NewReader(csvFile, japanese.ShiftJIS.NewDecoder()))
//ヘッダー部の読み飛ばし
reader.Read()
reader.Read()
var insertData []interface{}
for {
rec, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
return err
}
var csvData 地価公示
csvData.Fコード, _ = toInt(rec[1])
csvData.F対象年, _ = toInt(rec[2])
csvData.F標準地名 = rec[3]
csvData.F標準地番号用途, _ = toInt(rec[4])
csvData.F標準地番号連番, _ = toInt(rec[5])
csvData.F区市町村名 = rec[6]
csvData.F地番 = rec[7]
csvData.F住居表示 = rec[8]
csvData.F当年価格, _ = toInt(rec[9])
csvData.F前年価格, _ = toInt(rec[10])
csvData.F変動率, _ = toFloat(rec[11])
csvData.F地積, _ = toInt(rec[12])
insertData = append(insertData, csvData)
}
err = client.UseSession(context.Background(),
func(ctx mongo.SessionContext) error {
err := ctx.StartTransaction()
if err != nil {
return err
}
_, err = col.InsertMany(ctx, insertData)
if err != nil {
return err
}
return ctx.CommitTransaction(ctx)
})
return err
}
func main() {
if err := mainMain(); err != nil {
log.Fatal(err)
}
log.Println("normal end.")
}
地価公示データのFind
Find書式
Findは検索条件にマッチしたすべてのドキュメントを取得します
Find(context.Context, 検索条件, Find オプション)
オプションは**options.Find()で前回使用したoptions.FindOne()**ではありません。
Findのプログラム例
検索条件として当年価格が1000万円以上で変動率が高い5件を検索する例です
mongoシェル
db.col.find({"当年価格":{$gte:10000000}},{_id:0}).sort({"変動率":-1}).limit(5)
- cur.Next()は次のドキュメントの読み込み、ドキュメントが無いときはfalseを返す
- **cur.Decode()**は読み込んだドキュメントを取得します。Decodeできるタイプはいろいろありますので前回の投稿のFindOne編をご覧ください
find.go
package main
import (
"context"
"fmt"
"log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type 地価公示 struct {
Fコード int "コード"
F対象年 int "対象年"
F標準地名 string "標準地名"
F標準地番号用途 int "標準地番号用途"
F標準地番号連番 int "標準地番号連番"
F区市町村名 string "区市町村名"
F地番 string "地番"
F住居表示 string "住居表示"
F当年価格 int "当年価格"
F前年価格 int "前年価格"
F変動率 float64 "変動率"
F地積 int "地積"
}
func mainMain() error {
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
return err
}
if err = client.Connect(context.Background()); err != nil {
return err
}
defer client.Disconnect(context.Background())
col := client.Database("test").Collection("col")
findOptions := options.Find().SetProjection(bson.D{{"_id", 0}})
findOptions.SetLimit(5).SetSort(bson.D{{"変動率", -1}})
filter := bson.D{{"当年価格", bson.D{{"$gte", 1000 * 10000}}}}
cur, err := col.Find(context.Background(), filter, findOptions)
if err != nil {
return err
}
for cur.Next(context.Background()) {
var doc 地価公示
if err = cur.Decode(&doc); err != nil {
return err
}
//fmt.Printf("%+v\n", doc)
fmt.Printf("変動率:%g%%, 当年価格:%d万円, 地番:%s\n", doc.F変動率, doc.F当年価格/10000, doc.F地番)
}
return nil
}
func main() {
if err := mainMain(); err != nil {
log.Fatal(err)
}
log.Println("normal end.")
}
上記と同じ条件でAggregateを使ったプログラミング例
mongoシェル
db.col.aggregate([
{$match:{"当年価格":{$gte:10000000}}},
{$sort:{"変動率":-1}},
{$limit: 5},
{$project:{_id:0}}
])
go
filter := bson.D{{"当年価格", bson.D{{"$gte", 1000 * 10000}}}}
pipeline := bson.A{
bson.D{{"$match", filter}},
bson.D{{"$sort", bson.D{{"変動率", -1}}}},
bson.D{{"$limit", 5}},
bson.D{{"$project", bson.D{{"_id", 0}}}},
}
cur, err := col.Aggregate(context.Background(), pipeline)