序章

コミュニティが開発したソリューションに長年依存した後、MongoDBはがGoの公式ドライバーに取り組んでいることを発表しました。 2019年3月、この新しいドライバーは、v1.0.0 のリリースにより、本番環境に対応したステータスに達し、それ以降も継続的に更新されています。

他の公式のMongoDBドライバーと同様に、 GoドライバーはGoプログラミング言語に慣用的であり、GoプログラムのデータベースソリューションとしてMongoDBを使用する簡単な方法を提供します。 これはMongoDBAPIと完全に統合されており、APIのすべてのクエリ、インデックス作成、集計機能、およびその他の高度な機能を公開しています。 サードパーティのライブラリとは異なり、MongoDBエンジニアによって完全にサポートされるため、継続的な開発とメンテナンスを保証できます。

このチュートリアルでは、公式のMongoDBGoドライバーの使用を開始します。 ドライバーをインストールし、MongoDBデータベースに接続して、いくつかのCRUD操作を実行します。 その過程で、コマンドラインからタスクを管理するためのタスクマネージャープログラムを作成します。

前提条件

このチュートリアルでは、次のものが必要です。

  • MongoDBのインストール方法に従って、オペレーティングシステムにMongoDBをインストールします。 MongoDB 2.6以降は、MongoDBGoドライバーでサポートされている最小バージョンです。

Go v1.11または1.12を使用している場合は、Go Modulesが有効になっていることを確認して、 GO111MODULE 環境変数から on 次のように:

  1. export GO111MODULE="on"

環境変数の実装の詳細については、環境変数とシェル変数の読み取りと設定方法に関するこのチュートリアルをお読みください。

このガイドに示されているコマンドとコードは、Gov1.14.1とMongoDBv3.6.3でテストされています。

ステップ1—MongoDBGoドライバーをインストールする

このステップでは、MongoDB用のGo Driverパッケージをインストールし、プロジェクトにインポートします。 また、MongoDBデータベースに接続して、接続のステータスを確認します。

先に進み、ファイルシステムにこのチュートリアル用の新しいディレクトリを作成します。

  1. mkdir tasker

プロジェクトディレクトリを設定したら、次のコマンドを使用してディレクトリに変更します。

  1. cd tasker

次に、Goプロジェクトを go.mod ファイル。 このファイルは、プロジェクト要件を定義し、依存関係を正しいバージョンにロックします。

  1. go mod init

プロジェクトディレクトリが $GOPATH、モジュールのインポートパスを次のように指定する必要があります。

  1. go mod init github.com/<your_username>/tasker

この時点で、 go.mod ファイルは次のようになります。

go.mod
module github.com/<your_username>/tasker

go 1.14

次のコマンドを使用して、MongoDBGoドライバーをプロジェクトの依存関係として追加します。

  1. go get go.mongodb.org/mongo-driver

次のような出力が表示されます。

Output
go: downloading go.mongodb.org/mongo-driver v1.3.2 go: go.mongodb.org/mongo-driver upgrade => v1.3.2

この時点で、 go.mod ファイルは次のようになります。

go.mod
module github.com/<your_username>/tasker

go 1.14

require go.mongodb.org/mongo-driver v1.3.1 // indirect

次に、 main.go プロジェクトルートでファイルを作成し、テキストエディタで開きます。

  1. nano main.go

ドライバの使用を開始するには、次のパッケージをにインポートします main.go ファイル:

main.go
package main

import (
	"context"
	"log"

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

ここでは、MongoDBGoドライバーが提供するmongoおよびoptionsパッケージを追加します。

次に、インポートに続いて、新しいMongoDBクライアントを作成し、実行中のMongoDBサーバーに接続します。

main.go
. . .
var collection *mongo.Collection
var ctx = context.TODO()

func init() {
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")
	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}
}

mongo.Connect() を受け入れる Contextoptions.ClientOptions オブジェクト。接続文字列やその他のドライバ設定を設定するために使用されます。 オプションパッケージのドキュメントにアクセスして、使用可能な構成オプションを確認できます。

Context は、操作の実行を停止して戻るタイミングを示すタイムアウトまたは期限のようなものです。 特定の操作の実行速度が遅い場合に、実稼働システムのパフォーマンスが低下するのを防ぐのに役立ちます。 このコードでは、あなたは合格しています context.TODO() 現在使用するコンテキストがわからないが、将来追加する予定であることを示します。

次に、MongoDBサーバーが検出され、 Ping 方法。 内に次のコードを追加します init 関数:

main.go
. . .
    log.Fatal(err)
  }

  err = client.Ping(ctx, nil)
  if err != nil {
    log.Fatal(err)
  }
}

データベースへの接続中にエラーが発生した場合、アクティブなデータベース接続なしでプログラムを実行し続ける意味がないため、問題を修正しようとするとプログラムがクラッシュするはずです。

次のコードを追加して、データベースを作成します。

main.go
. . .
  err = client.Ping(ctx, nil)
  if err != nil {
    log.Fatal(err)
  }

  collection = client.Database("tasker").Collection("tasks")
}

あなたは tasker データベースと task 作成するタスクを保存するコレクション。 あなたも設定します collection パッケージレベルの変数として、パッケージ全体でデータベース接続を再利用できるようにします。

ファイルを保存して終了します。

フル main.go この時点で次のようになります。

main.go
package main

import (
	"context"
	"log"

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

var collection *mongo.Collection
var ctx = context.TODO()

func init() {
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")
	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}

	err = client.Ping(ctx, nil)
	if err != nil {
		log.Fatal(err)
	}

	collection = client.Database("tasker").Collection("tasks")
}

Goドライバーを使用してMongoDBサーバーに接続するようにプログラムを設定しました。 次のステップでは、タスクマネージャプログラムの作成に進みます。

ステップ2—CLIプログラムの作成

このステップでは、よく知られている cli パッケージをインストールして、タスクマネージャープログラムの開発を支援します。 最新のコマンドラインツールをすばやく作成するために利用できるインターフェイスを提供します。 たとえば、このパッケージは、よりgitに似たコマンドラインエクスペリエンスのために、プログラムのサブコマンドを定義する機能を提供します。

次のコマンドを実行して、パッケージを依存関係として追加します。

  1. go get github.com/urfave/cli/v2

次に、 main.go 再度ファイル:

  1. nano main.go

次の強調表示されたコードを main.go ファイル:

main.go
package main

import (
	"context"
	"log"
	"os"

	"github.com/urfave/cli/v2"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)
. . .

をインポートします cli 述べたようにパッケージ。 また、 os パッケージ。コマンドライン引数をプログラムに渡すために使用します。

次のコードを init CLIプログラムを作成し、コードをコンパイルする関数:

main.go
. . .
func main() {
	app := &cli.App{
		Name:     "tasker",
		Usage:    "A simple CLI program to manage your tasks",
		Commands: []*cli.Command{},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

このスニペットは、というCLIプログラムを作成します tasker プログラムの実行時に出力される簡単な使用法の説明を追加します。 The Commands スライスは、プログラムのコマンドを追加する場所です。 The Run コマンドは、引数スライスを適切なコマンドに解析します。

ファイルを保存して終了します。

プログラムをビルドして実行するために必要なコマンドは次のとおりです。

  1. go run main.go

次の出力が表示されます。

Output
NAME: tasker - A simple CLI program to manage your tasks USAGE: main [global options] command [command options] [arguments...] COMMANDS: help, h Shows a list of commands or help for one command GLOBAL OPTIONS: --help, -h show help (default: false)

プログラムが実行され、ヘルプテキストが表示されます。これは、プログラムで何ができるか、およびその使用方法を学習するのに便利です。

次のステップでは、MongoDBでのタスクの管理に役立つサブコマンドを追加することで、プログラムの有用性を向上させます。

ステップ3—タスクの作成

このステップでは、を使用してCLIプログラムにサブコマンドを追加します。 cli パッケージ。 このセクションの最後で、新しいタスクを使用して、MongoDBデータベースに新しいタスクを追加できるようになります。 add CLIプログラムのコマンド。

あなたのを開くことから始めます main.go ファイル:

  1. nano main.go

次に、 go.mongodb.org/mongo-driver/bson/primitive time 、およびerrorsパッケージをインポートします。

main.go
package main

import (
	"context"
	"errors"
	"log"
	"os"
	"time"

	"github.com/urfave/cli/v2"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)
. . .

次に、データベース内の単一のタスクを表す新しい構造体を作成し、その直前に挿入します。 main 関数:

main.go
. . .
type Task struct {
	ID        primitive.ObjectID `bson:"_id"`
	CreatedAt time.Time          `bson:"created_at"`
	UpdatedAt time.Time          `bson:"updated_at"`
	Text      string             `bson:"text"`
	Completed bool               `bson:"completed"`
}
. . .

あなたは primitive MongoDBが使用するため、各タスクのIDのタイプを設定するパッケージ ObjectIDs _id デフォルトではフィールド。 MongoDBのもう1つのデフォルトの動作は、シリアル化されるときに、エクスポートされた各フィールドのキーとして小文字のフィールド名が使用されることですが、これは次を使用して変更できます。 bson 構造体タグ。

次に、のインスタンスを受け取る関数を作成します Task そしてそれをデータベースに保存します。 次のスニペットを追加します main 関数:

main.go
. . .
func createTask(task *Task) error {
	_, err := collection.InsertOne(ctx, task)
  return err
}
. . .

The collection.InsertOne() メソッドは、提供されたタスクをデータベースコレクションに挿入し、挿入されたドキュメントのIDを返します。 このIDは必要ないため、アンダースコア演算子に割り当てて破棄します。

次のステップは、新しいタスクを作成するための新しいコマンドをタスクマネージャープログラムに追加することです。 それを呼びましょう add:

main.go
. . .
func main() {
	app := &cli.App{
		Name:  "tasker",
		Usage: "A simple CLI program to manage your tasks",
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a task to the list",
				Action: func(c *cli.Context) error {
					str := c.Args().First()
					if str == "" {
						return errors.New("Cannot add an empty task")
					}

					task := &Task{
						ID:        primitive.NewObjectID(),
						CreatedAt: time.Now(),
						UpdatedAt: time.Now(),
						Text:      str,
						Completed: false,
					}

					return createTask(task)
				},
			},
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

CLIプログラムに追加されたすべての新しいコマンドは、 Commands スライス。 それぞれが名前、使用法の説明、およびアクションで構成されています。 これは、コマンドの実行時に実行されるコードです。

このコードでは、最初の引数を次のように収集します。 add それを使用して設定します Text 新しいのプロパティ Task 他のプロパティに適切なデフォルトを割り当てている間、インスタンス。 その後、新しいタスクはに渡されます createTask、これはタスクをデータベースに挿入し、 nil すべてがうまくいけば、コマンドが終了します。

ファイルを保存して終了します。

を使用していくつかのタスクを追加してテストしてください add 指図。 成功した場合、画面にエラーは表示されません。

  1. go run main.go add "Learn Go"
  2. go run main.go add "Read a book"

タスクを正常に追加できるようになったので、データベースに追加したすべてのタスクを表示する方法を実装しましょう。

ステップ4—すべてのタスクを一覧表示する

コレクション内のドキュメントの一覧表示は、 collection.Find() メソッド。フィルターと、結果をデコードできる値へのポインターが必要です。 その戻り値はCursorであり、一度に1つずつ繰り返してデコードできるドキュメントのストリームを提供します。 カーソルが使い果たされると、カーソルは閉じられます。

あなたの main.go ファイル:

  1. nano main.go

必ずbsonパッケージをインポートしてください。

main.go
package main

import (
	"context"
	"errors"
	"log"
	"os"
	"time"

	"github.com/urfave/cli/v2"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)
. . .

次に、直後に次の関数を作成します createTask:

main.go
. . .
func getAll() ([]*Task, error) {
  // passing bson.D{{}} matches all documents in the collection
	filter := bson.D{{}}
	return filterTasks(filter)
}

func filterTasks(filter interface{}) ([]*Task, error) {
	// A slice of tasks for storing the decoded documents
	var tasks []*Task

	cur, err := collection.Find(ctx, filter)
	if err != nil {
		return tasks, err
	}

	for cur.Next(ctx) {
		var t Task
		err := cur.Decode(&t)
		if err != nil {
			return tasks, err
		}

		tasks = append(tasks, &t)
	}

	if err := cur.Err(); err != nil {
		return tasks, err
	}

  // once exhausted, close the cursor
	cur.Close(ctx)

	if len(tasks) == 0 {
		return tasks, mongo.ErrNoDocuments
	}

	return tasks, nil
}

BSON(バイナリエンコードされたJSON)は、MongoDBデータベースおよび bson パッケージは、GoでBSONオブジェクトを操作するのに役立ちます。 The bson.D で使用されるタイプ getAll() 関数はBSONドキュメントを表し、プロパティの順序が重要な場合に使用されます。 通過することによって bson.D{{}} フィルタとして filterTasks()、コレクション内のすべてのドキュメントを照合することを示しています。

の中に filterTasks() 関数では、によって返されるカーソルを繰り返し処理します。 collection.Find() メソッドを作成し、各ドキュメントを次のインスタンスにデコードします。 Task. 各 Task 次に、関数の開始時に作成されたタスクのスライスに追加されます。 カーソルが使い果たされると、カーソルが閉じられ、 tasks スライスが返されます。

すべてのタスクを一覧表示するコマンドを作成する前に、 tasks 標準出力に出力します。 colorパッケージを使用して出力を色付けします。

このパッケージを使用する前に、次のコマンドを使用してインストールしてください。

  1. go get gopkg.in/gookit/color.v1

次の出力が表示されます。

Output
go: downloading gopkg.in/gookit/color.v1 v1.1.6 go: gopkg.in/gookit/color.v1 upgrade => v1.1.6

そしてそれをあなたの main.go と一緒にファイル fmt パッケージ:

main.go
package main

import (
	"context"
	"errors"
  "fmt"
	"log"
	"os"
	"time"

	"github.com/urfave/cli/v2"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gopkg.in/gookit/color.v1"
)
. . .

次に、新しいを作成します printTasks あなたの次の機能 main 関数:

main.go
. . .
func printTasks(tasks []*Task) {
	for i, v := range tasks {
		if v.Completed {
			color.Green.Printf("%d: %s\n", i+1, v.Text)
		} else {
			color.Yellow.Printf("%d: %s\n", i+1, v.Text)
		}
	}
}
. . .

これ printTasks 関数はのスライスを取ります tasks、それぞれを繰り返し、完了したタスクを示す緑色と未完了のタスクを示す黄色を使用して、標準出力に出力します。

先に進み、次の強調表示された行を追加して、新しいを作成します all にコマンド Commands スライス。 このコマンドは、追加されたすべてのタスクを標準出力に出力します。

main.go
. . .
func main() {
	app := &cli.App{
		Name:  "tasker",
		Usage: "A simple CLI program to manage your tasks",
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a task to the list",
				Action: func(c *cli.Context) error {
					str := c.Args().First()
					if str == "" {
						return errors.New("Cannot add an empty task")
					}

					task := &Task{
						ID:        primitive.NewObjectID(),
						CreatedAt: time.Now(),
						UpdatedAt: time.Now(),
						Text:      str,
						Completed: false,
					}

					return createTask(task)
				},
			},
			{
				Name:    "all",
				Aliases: []string{"l"},
				Usage:   "list all tasks",
				Action: func(c *cli.Context) error {
					tasks, err := getAll()
					if err != nil {
						if err == mongo.ErrNoDocuments {
							fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
							return nil
						}

						return err
					}

					printTasks(tasks)
					return nil
				},
			},
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

. . .

The all コマンドは、データベースに存在するすべてのタスクを取得し、それらを標準出力に出力します。 タスクが存在しない場合は、代わりに新しいタスクを追加するためのプロンプトが出力されます。

ファイルを保存して終了します。

を使用してプログラムをビルドして実行します all 指図:

  1. go run main.go all

これまでに追加したすべてのタスクが一覧表示されます。

Output
1: Learn Go 2: Read a book

データベース内のすべてのタスクを表示できるようになったので、次のステップでタスクを完了としてマークする機能を追加しましょう。

ステップ5—タスクの完了

このステップでは、という新しいサブコマンドを作成します done これにより、データベース内の既存のタスクを完了としてマークできます。 タスクを完了としてマークするには、 collection.FindOneAndUpdate() 方法。 コレクション内のドキュメントを検索し、そのプロパティの一部またはすべてを更新できます。 この方法では、ドキュメントを見つけるためのフィルターと、操作を説明するための更新ドキュメントが必要です。 これらは両方ともを使用して構築されています bson.D 種類。

あなたのを開くことから始めます main.go ファイル:

  1. nano main.go

次のスニペットを filterTasks 関数:

main.go
. . .
func completeTask(text string) error {
	filter := bson.D{primitive.E{Key: "text", Value: text}}

	update := bson.D{primitive.E{Key: "$set", Value: bson.D{
		primitive.E{Key: "completed", Value: true},
	}}}

	t := &Task{}
	return collection.FindOneAndUpdate(ctx, filter, update).Decode(t)
}
. . .

この関数は、textプロパティが text パラメータ。 The update ドキュメントは、 completed プロパティをに設定する true. にエラーがある場合 FindOneAndUpdate() 操作、それはによって返されます completeTask(). さもないと nil が返されます。

次に、新しいものを追加しましょう done タスクを完了としてマークするCLIプログラムへのコマンド:

main.go
. . .
func main() {
	app := &cli.App{
		Name:  "tasker",
		Usage: "A simple CLI program to manage your tasks",
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a task to the list",
				Action: func(c *cli.Context) error {
					str := c.Args().First()
					if str == "" {
						return errors.New("Cannot add an empty task")
					}

					task := &Task{
						ID:        primitive.NewObjectID(),
						CreatedAt: time.Now(),
						UpdatedAt: time.Now(),
						Text:      str,
						Completed: false,
					}

					return createTask(task)
				},
			},
			{
				Name:    "all",
				Aliases: []string{"l"},
				Usage:   "list all tasks",
				Action: func(c *cli.Context) error {
					tasks, err := getAll()
					if err != nil {
						if err == mongo.ErrNoDocuments {
							fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
							return nil
						}

						return err
					}

					printTasks(tasks)
					return nil
				},
			},
			{
				Name:    "done",
				Aliases: []string{"d"},
				Usage:   "complete a task on the list",
				Action: func(c *cli.Context) error {
					text := c.Args().First()
					return completeTask(text)
				},
			},
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

. . .

に渡された引数を使用します done 最初のドキュメントを検索するコマンド text プロパティが一致します。 見つかった場合、 completed ドキュメントのプロパティはに設定されています true.

ファイルを保存して終了します。

次に、でプログラムを実行します done 指図:

  1. go run main.go done "Learn Go"

を使用する場合 all もう一度コマンドを実行すると、完了としてマークされたタスクが緑色で印刷されていることがわかります。

  1. go run main.go all

まだ実行されていないタスクのみを表示したい場合があります。 次にその機能を追加します。

手順6—保留中のタスクのみを表示する

このステップでは、MongoDBドライバーを使用してデータベースから保留中のタスクを取得するコードを組み込みます。 保留中のタスクとは、 completed プロパティはに設定されています false.

まだ完了していないタスクを取得する新しい関数を追加しましょう。 あなたの main.go ファイル:

  1. nano main.go

次に、このスニペットを次のように追加します completeTask 関数:

main.go
. . .
func getPending() ([]*Task, error) {
	filter := bson.D{
		primitive.E{Key: "completed", Value: false},
	}

	return filterTasks(filter)
}
. . .

フィルタを作成するには、 bsonprimitive MongoDBドライバーからのパッケージ。これは、次のドキュメントと一致します。 completed プロパティはに設定されています false. その後、保留中のタスクのスライスが呼び出し元に返されます。

保留中のタスクを一覧表示する新しいコマンドを作成する代わりに、コマンドなしでプログラムを実行するときのデフォルトのアクションにしましょう。 これを行うには、 Action 次のようにプログラムのプロパティ:

main.go
. . .
func main() {
	app := &cli.App{
		Name:  "tasker",
		Usage: "A simple CLI program to manage your tasks",
		Action: func(c *cli.Context) error {
			tasks, err := getPending()
			if err != nil {
				if err == mongo.ErrNoDocuments {
					fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
					return nil
				}

				return err
			}

			printTasks(tasks)
			return nil
		},
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a task to the list",
				Action: func(c *cli.Context) error {
					str := c.Args().First()
					if str == "" {
						return errors.New("Cannot add an empty task")
					}

					task := &Task{
						ID:        primitive.NewObjectID(),
						CreatedAt: time.Now(),
						UpdatedAt: time.Now(),
						Text:      str,
						Completed: false,
					}

					return createTask(task)
				},
			},
. . .

The Action プログラムがサブコマンドなしで実行されると、プロパティはデフォルトのアクションを実行します。 これは、保留中のタスクを一覧表示するためのロジックが配置される場所です。 The getPending() 関数が呼び出され、結果のタスクが次を使用して標準出力に出力されます。 printTasks(). 保留中のタスクがない場合は、代わりにプロンプトが表示され、ユーザーにを使用して新しいタスクを追加するように促します。 add 指図。

ファイルを保存して終了します。

コマンドを追加せずに今すぐプログラムを実行すると、データベース内のすべての保留中のタスクが一覧表示されます。

  1. go run main.go

次の出力が表示されます。

Output
1: Read a book

未完了のタスクを一覧表示できるようになったので、完了したタスクのみを表示できる別のコマンドを追加しましょう。

ステップ7—完了したタスクの表示

このステップでは、新しいものを追加します finished 完了したタスクをデータベースからフェッチして画面に表示するサブコマンド。 これには、タスクのフィルタリングと返却が含まれます。 completed プロパティはに設定されています true.

あなたの main.go ファイル:

  1. nano main.go

次に、ファイルの最後に次のコードを追加します。

main.go
. . .
func getFinished() ([]*Task, error) {
	filter := bson.D{
		primitive.E{Key: "completed", Value: true},
	}

	return filterTasks(filter)
}
. . .

に似ています getPending() 関数、あなたは追加しました getFinished() 完了したタスクのスライスを返す関数。 この場合、フィルターには completed プロパティをに設定 true したがって、この条件に一致するドキュメントのみが返されます。

次に、 finished 完了したすべてのタスクを出力するコマンド:

main.go
. . .
func main() {
	app := &cli.App{
		Name:  "tasker",
		Usage: "A simple CLI program to manage your tasks",
		Action: func(c *cli.Context) error {
			tasks, err := getPending()
			if err != nil {
				if err == mongo.ErrNoDocuments {
					fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
					return nil
				}

				return err
			}

			printTasks(tasks)
			return nil
		},
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a task to the list",
				Action: func(c *cli.Context) error {
					str := c.Args().First()
					if str == "" {
						return errors.New("Cannot add an empty task")
					}

					task := &Task{
						ID:        primitive.NewObjectID(),
						CreatedAt: time.Now(),
						UpdatedAt: time.Now(),
						Text:      str,
						Completed: false,
					}

					return createTask(task)
				},
			},
			{
				Name:    "all",
				Aliases: []string{"l"},
				Usage:   "list all tasks",
				Action: func(c *cli.Context) error {
					tasks, err := getAll()
					if err != nil {
						if err == mongo.ErrNoDocuments {
							fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
							return nil
						}

						return err
					}

					printTasks(tasks)
					return nil
				},
			},
			{
				Name:    "done",
				Aliases: []string{"d"},
				Usage:   "complete a task on the list",
				Action: func(c *cli.Context) error {
					text := c.Args().First()
					return completeTask(text)
				},
			},
			{
				Name:    "finished",
				Aliases: []string{"f"},
				Usage:   "list completed tasks",
				Action: func(c *cli.Context) error {
					tasks, err := getFinished()
					if err != nil {
						if err == mongo.ErrNoDocuments {
							fmt.Print("Nothing to see here.\nRun `done 'task'` to complete a task")
							return nil
						}

						return err
					}

					printTasks(tasks)
					return nil
				},
			},
		}
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}
. . .

The finished コマンドは、そのタスクを取得します completed プロパティはに設定されています true 経由 getFinished() ここで作成された関数。 次に、それをに渡します printTasks 標準出力に出力されるように機能します。

ファイルを保存して終了します。

次のコマンドを実行します。

  1. go run main.go finished

次の出力が表示されます。

Output
1: Learn Go

最後のステップでは、データベースからタスクを削除するオプションをユーザーに提供します。

ステップ8—タスクを削除する

このステップでは、新しいものを追加します delete ユーザーがデータベースからタスクを削除できるようにするサブコマンド。 1つのタスクを削除するには、 collection.DeleteOne() MongoDBドライバーからのメソッド。 また、削除するドキュメントを照合するためにフィルターに依存しています。

あなたの main.go もう一度ファイル:

  1. nano main.go

これを追加 deleteTask 直後にデータベースからタスクを削除する機能 getFinished 関数:

main.go
. . .
func deleteTask(text string) error {
	filter := bson.D{primitive.E{Key: "text", Value: text}}

	res, err := collection.DeleteOne(ctx, filter)
	if err != nil {
		return err
	}

	if res.DeletedCount == 0 {
		return errors.New("No tasks were deleted")
	}

	return nil
}
. . .

これ deleteTask メソッドは、削除するタスク項目を表す文字列引数を取ります。 フィルタは、そのタスクアイテムに一致するように構築されます text プロパティは文字列引数に設定されます。 フィルタをに渡します DeleteOne() コレクション内のアイテムに一致し、それを削除するメソッド。

あなたはチェックすることができます DeletedCount 結果のプロパティ DeleteOne ドキュメントが削除されたかどうかを確認する方法。 フィルタが削除するドキュメントと一致しない場合、 DeletedCount はゼロになり、その場合はエラーを返すことができます。

今すぐ新しいを追加します rm 強調表示されているコマンド:

main.go
. . .
func main() {
	app := &cli.App{
		Name:  "tasker",
		Usage: "A simple CLI program to manage your tasks",
		Action: func(c *cli.Context) error {
			tasks, err := getPending()
			if err != nil {
				if err == mongo.ErrNoDocuments {
					fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
					return nil
				}

				return err
			}

			printTasks(tasks)
			return nil
		},
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a task to the list",
				Action: func(c *cli.Context) error {
					str := c.Args().First()
					if str == "" {
						return errors.New("Cannot add an empty task")
					}

					task := &Task{
						ID:        primitive.NewObjectID(),
						CreatedAt: time.Now(),
						UpdatedAt: time.Now(),
						Text:      str,
						Completed: false,
					}

					return createTask(task)
				},
			},
			{
				Name:    "all",
				Aliases: []string{"l"},
				Usage:   "list all tasks",
				Action: func(c *cli.Context) error {
					tasks, err := getAll()
					if err != nil {
						if err == mongo.ErrNoDocuments {
							fmt.Print("Nothing to see here.\nRun `add 'task'` to add a task")
							return nil
						}

						return err
					}

					printTasks(tasks)
					return nil
				},
			},
			{
				Name:    "done",
				Aliases: []string{"d"},
				Usage:   "complete a task on the list",
				Action: func(c *cli.Context) error {
					text := c.Args().First()
					return completeTask(text)
				},
			},
			{
				Name:    "finished",
				Aliases: []string{"f"},
				Usage:   "list completed tasks",
				Action: func(c *cli.Context) error {
					tasks, err := getFinished()
					if err != nil {
						if err == mongo.ErrNoDocuments {
							fmt.Print("Nothing to see here.\nRun `done 'task'` to complete a task")
							return nil
						}

						return err
					}

					printTasks(tasks)
					return nil
				},
			},
			{
				Name:  "rm",
				Usage: "deletes a task on the list",
				Action: func(c *cli.Context) error {
					text := c.Args().First()
					err := deleteTask(text)
					if err != nil {
						return err
					}

					return nil
				},
			},
		}
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}
. . .

以前に追加された他のすべてのサブコマンドと同様に、 rm コマンドは最初の引数を使用してデータベース内のタスクを照合し、それを削除します。

ファイルを保存して終了します。

サブコマンドを渡さずにプログラムを実行することにより、保留中のタスクを一覧表示できます。

  1. go run main.go
Output
1: Read a book

の実行 rm のサブコマンド "Read a book" タスクはそれをデータベースから削除します:

  1. go run main.go rm "Read a book"

保留中のすべてのタスクを再度リストすると、 "Read a book" タスクは表示されなくなり、代わりに新しいタスクを追加するためのプロンプトが表示されます。

  1. go run main.go
Output
Nothing to see here Run `add 'task'` to add a task

このステップでは、データベースからタスクを削除する関数を追加しました。

結論

タスクマネージャーのコマンドラインプログラムを正常に作成し、その過程でMongoDBGoドライバーを使用するための基本を学びました。

GoDoc でMongoDBGoドライバーの完全なドキュメントを確認して、ドライバーの使用が提供する機能の詳細を確認してください。 集約またはトランザクションの使用について説明しているドキュメントは、特に興味深いものになる可能性があります。

このチュートリアルの最終的なコードは、このGitHubリポジトリで表示できます。