4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MongoDBの Offical Go言語 Driverを使ってみる(3)Find

Posted at

「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)
4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?