goでmongodbからdocumentの取得

# はじめに
WordPressでブログを運用しているのですが、文章を全てMarkdownで保持しておきたいと思い自前でブログシステムを書いています[^1]。1年近く前にWeb屋をリストラされてしまい今は違う仕事をしているので、せっかくなので知らない技術でやってみようとGo(echo)とMongoDBを使って作っています。そこでの経験を書いていければと思います。Goについてはまともに始めて3ヶ月位で、体系的に、というよりは作りながら書籍/ドキュメントを読んでいるので誤りがあれば訂正いただけると幸いです。

# 開発環境
- Windows10
- Visual Studio Code
- go version go1.15.5 windows/amd64
- MongoDB server version: 4.4.3
- go.mongodb.org/mongo-driver v1.4.5

開発環境はWindowsですが、CentOS7上で動作は確認しています。

# MongoDB
このようなCollectionになっています。
![1611919233416.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595802/20b31784-4aca-878c-7b72-d56ff880e626.png)

```powershell:database/User/indexの作成
use doblog  
db.createUser( { user:"USER", pwd:"PASSWORD", roles:[{ "role" : "dbOwner", "db" : "doblog" }] } );  
db.entries.createIndex({entryCode: 1},{unique: true});
db.entries.createIndex({entryId: 1},{unique: true});  
db.entries.createIndex({isPublished: 1, publishDate: -1});
db.entries.createIndex({category: 1, isPublished: 1, publishDate: -1});
```
unique:trueでユニークフィールドに。他はfind用。indexが効いているかは[explain](https://docs.mongodb.com/manual/reference/method/db.collection.explain/)でチェック。

```powershell:(例
db.entries.find({category: "php", isPublished: 1}).sort({publishDate: -1}).limit(1).explain();
```

参考にしました。 [https://qiita.com/koshilife/items/79a8d59fa0973c16de57](https://qiita.com/koshilife/items/79a8d59fa0973c16de57)

WordPressからのデータ移行はphpで書いたのですが省略してます。


# mongo-driver
```powershell
go get -u go.mongodb.org/mongo-driver/mongo
```

# code
```golang:main.go
package main

import (
	"context"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// Entry for get data from mongodb
type Entry struct {
	EntryID     int32    `bson:"entryId"`
	EntryCode   string   `bson:"entryCode"`
	PublishDate string   `bson:"publishDate"`
	Title       string   `bson:"title"`
	Content     string   `bson:"content"`
	Category    []string `bson:"category"`
	IsPublished int32    `bson:"isPublished"`
	AuthorID    int32    `bson:"authorId"`
	CreatedAt   string   `bson:"createdAt"`
	UpdatedAt   string   `bson:"updatedAt"`
}

func main() {
	//
	// mongodb init
	//
	ctx := context.Background()
	credential := options.Credential{
		AuthSource: "doblog",
		Username:   "USER",
		Password:   "PASSWORD",
	}
	client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://127.0.0.1:27017").SetAuth(credential))
	defer client.Disconnect(ctx)
	//
	// get entries (publishDateの降順でソート)
	//
	var entryList []Entry
	entries := client.Database("doblog").Collection("entries")
	// publishDateの降順
	findOption := options.Find().SetSort(bson.D{{Key: "publishDate", Value: -1}})
	// PaginatorなどでLimit, Offsetを使いたい場合はこう
	// findOption := options.Find().SetSort(bson.D{{Key: "publishDate", Value: -1}}).SetSkip(10).SetLimit(5)

	// SQLでの select * from entries where isPublished = 1 と同様
	cur, err := entries.Find(ctx, bson.D{{Key: "isPublished", Value: 1}}, findOption)
	if err != nil {
		fmt.Println(err)

	}
	defer cur.Close(ctx)
	// findはスライス等で返ってこない。 *Cursol型で返ってくるので下記のようにループ回して取得
	for cur.Next(ctx) {
		var result Entry
		err := cur.Decode(&result)
		if err != nil {
			fmt.Println(err)
		}
		entryList = append(entryList, result)
	}
	fmt.Println(entryList)

	//
	// get entry (entryCodeを指定して一件取得)
	//
	var entry Entry
	err = entries.FindOne(ctx, bson.D{{Key: "entryCode", Value: "net-core-3-0-excel-epplus"}, {Key: "isPublished", Value: 1}}).Decode(&entry)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(entry)
}

```

オレオレブログパッケージからコードを抜き出していますが、挙動については確認してから掲載しています。

[^1]: プラグインを使ってMarkdownでpost_contentを書いていたのですが、wp_postを覗いたところ妙なタグで埋め尽くされていたり、魔窟のようになっていたのでこれを機に作ろうかなと。いろいろなプラグインを試したのが悪手だったのかも。