Der Autor wählte die Free Software Foundation, um eine Spende im Rahmen des Programms Write for DOnations zu erhalten.
Nachdem MongoDB sich viele Jahre lang auf von der Community entwickelte Lösungen verlassen hatte, gab MongoDB bekannt, dass sie an einem offiziellen Treiber für Go arbeiten. Im März 2019 erreichte dieser neue Treiber mit der Veröffentlichung von v1.0.0 den Status „Produktionsbereit“ und wurde seitdem kontinuierlich aktualisiert.
Wie die anderen offiziellen MongoDB-Treiber ist der Go-Treiber für die Go-Programmiersprache typisch und bietet eine einfache Möglichkeit, MongoDB als Datenbanklösung für ein Go-Programm zu verwenden. Er ist vollständig in die MongoDB-API integriert und stellt alle Abfrage-, Indexierungs- und Aggregationsfunktionen der API sowie andere erweiterte Funktionen zur Verfügung. Im Gegensatz zu Bibliotheken von Drittanbietern wird er von MongoDB-Ingenieuren vollständig unterstützt, sodass Sie sicher sein können, dass er weiterentwickelt und gewartet wird.
In diesem Tutorial lernen Sie den offiziellen MongoDB Go-Treiber kennen. Sie installieren den Treiber, stellen eine Verbindung zu einer MongoDB-Datenbank her und führen mehrere CRUD-Vorgänge aus. Dabei erstellen Sie ein Task-Manager-Programm zum Verwalten von Aufgaben über die Befehlszeile.
Für dieses Tutorial benötigen Sie Folgendes:
tasker
bezeichnet. Sie müssen Go v1.11 oder höher auf Ihrem Computer mit aktivierten Go-Modulen installiert haben.Wenn Sie Go v1.11 oder 1.12 verwenden, stellen Sie sicher, dass Go Modules aktiviert ist, indem Sie die Umgebungsvariable GO111MODULE
wie folgt auf on
setzen:
- export GO111MODULE="on"
Weitere Informationen zum Implementieren von Umgebungsvariablen finden Sie in diesem Tutorial zum Lesen und Festlegen von Umgebungs- und Shell-Variablen.
Die in diesem Leitfaden gezeigten Befehle und Codes wurden mit Go v1.14.1 und MongoDB v3.6.3 getestet.
In diesem Schritt installieren Sie das Paket Go Driver für MongoDB und importieren es in Ihr Projekt. Außerdem stellen Sie eine Verbindung zu Ihrer MongoDB-Datenbank her und überprüfen den Status der Verbindung.
Fahren Sie fort und erstellen Sie ein neues Verzeichnis für dieses Tutorial in Ihrem Dateisystem:
- mkdir tasker
Sobald Ihr Projektverzeichnis eingerichtet ist, ändern Sie es mit dem folgenden Befehl:
- cd tasker
Initialisieren Sie als Nächstes das Go-Projekt mit einer go.mod
-Datei. Diese Datei definiert die Projektanforderungen und die Abhängigkeiten ihrer richtigen Versionen:
- go mod init
Wenn Ihr Projektverzeichnis außerhalb von $GOPATH
ist, müssen Sie den Importpfad für Ihr Modul wie folgt angeben:
- go mod init github.com/<your_username>/tasker
Nun sieht Ihre Datei go.mod
wie folgt aus:
module github.com/<your_username>/tasker
go 1.14
Fügen Sie mit dem folgenden Befehl den MongoDB Go-Treiber als eine Abhängigkeit für Ihr Projekt hinzu:
- go get go.mongodb.org/mongo-driver
Sie sehen eine Ausgabe wie die folgende:
Outputgo: downloading go.mongodb.org/mongo-driver v1.3.2
go: go.mongodb.org/mongo-driver upgrade => v1.3.2
Nun sieht Ihre Datei go.mod
wie folgt aus:
module github.com/<your_username>/tasker
go 1.14
require go.mongodb.org/mongo-driver v1.3.1 // indirect
Erstellen Sie als Nächstes eine main.go
-Datei in Ihrem Projektstamm und öffnen Sie sie in Ihrem Texteditor:
- nano main.go
Importieren Sie die folgenden Pakete in Ihre main.go
-Datei, um mit dem Treiber zu beginnen:
package main
import (
"context"
"log"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
Hier fügen Sie die Pakete mongo
und options
hinzu, die der MongoDB Go-Treiber bereitstellt.
Erstellen Sie nach Ihren Importen einen neuen MongoDB-Client und stellen Sie eine Verbindung zu Ihrem laufenden MongoDB-Server her:
. . .
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()
akzeptiert ein Objekt Context
und ein options.ClientOptions
-Objekt, mit denen die Verbindungszeichenfolge und andere Treibereinstellungen festgelegt werden. In der Dokumentation zum Optionspaket finden Sie Informationen zu den verfügbaren Konfigurationsoptionen.
Context ist wie eine Zeitüberschreitung oder eine Frist, die angibt, wann ein Vorgang nicht mehr ausgeführt und zurückgegeben werden soll. Dies hilft, Leistungseinbußen auf Produktionssystemen zu vermeiden, wenn bestimmte Vorgänge langsam ausgeführt werden. In diesem Code übergeben Sie context.TODO()
, um anzuzeigen, dass Sie nicht sicher sind, welchen Kontext Sie derzeit verwenden sollen, aber Sie planen, in Zukunft einen hinzuzufügen.
Stellen Sie als Nächstes sicher, dass Ihr MongoDB-Server mithilfe der Ping
-Methode gefunden und erfolgreich verbunden wurde. Fügen Sie den folgenden Code in die init
-Funktion ein:
. . .
log.Fatal(err)
}
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal(err)
}
}
Wenn beim Herstellen einer Verbindung zur Datenbank Fehler auftreten, sollte das Programm abstürzen, während Sie versuchen, das Problem zu beheben, da es keinen Sinn macht, das Programm ohne aktive Datenbankverbindung auszuführen.
Fügen Sie den folgenden Code hinzu, um eine Datenbank zu erstellen:
. . .
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal(err)
}
collection = client.Database("tasker").Collection("tasks")
}
Sie erstellen eine tasker
-Datenbank und eine task
-Sammlung, um die zu erstellenden Aufgaben zu speichern. Sie richten collection
auch als Variable auf Paketebene ein, damit Sie die Datenbankverbindung im gesamten Paket wiederverwenden können.
Speichern und schließen Sie die Datei.
Das vollständige main.go
ist nun wie folgt:
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")
}
Sie haben Ihr Programm eingerichtet, um über den Go-Treiber eine Verbindung zu Ihrem MongoDB-Server zu erhalten. Im nächsten Schritt erstellen Sie Ihr Task-Manager-Programm.
In diesem Schritt installieren Sie das bekannte cli
-Paket, um die Entwicklung Ihres Task-Manager-Programms zu unterstützen. Es bietet eine Schnittstelle, über die Sie schnell moderne Befehlszeilentools erstellen können. Dieses Paket bietet beispielsweise die Möglichkeit, Unterbefehle für Ihr Programm zu definieren, um eine git-ähnliche Befehlszeilenerfahrung zu erzielen.
Führen Sie den folgenden Befehl aus, um das Paket als Abhängigkeit hinzuzufügen:
- go get github.com/urfave/cli/v2
Öffnen Sie als Nächstes Ihre main.go
-Datei erneut:
- nano main.go
Fügen Sie Ihrer main.go
-Datei den folgenden hervorgehobenen Code hinzu:
package main
import (
"context"
"log"
"os"
"github.com/urfave/cli/v2"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
. . .
Sie importieren das cli
-Paket wie erwähnt. Außerdem importieren Sie das Paket os
, das Sie verwenden, um Befehlszeilenargumente an Ihr Programm zu übergeben:
Fügen Sie nach Ihrer init
-Funktion den folgenden Code hinzu, um Ihr CLI-Programm zu erstellen und den Code zu kompilieren:
. . .
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)
}
}
Dieses Snippet erstellt ein CLI-Programm namens tasker
und fügt eine kurze Verwendungsbeschreibung hinzu, die beim Ausführen des Programms ausgedruckt wird. Im Befehlsfenster
fügen Sie Befehle für Ihr Programm hinzu. Der Befehl Run
analysiert die Argumente auf den entsprechenden Befehl.
Speichern und schließen Sie Ihre Datei.
Hier ist der Befehl, den Sie zum Erstellen und Ausführen des Programms benötigen:
- go run main.go
Sie sehen die folgende Ausgabe:
OutputNAME:
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)
Das Programm wird ausgeführt und zeigt einen Hilfetext an, in dem Sie erfahren, was das Programm kann und wie es verwendet wird.
In den nächsten Schritten verbessern Sie die Nützlichkeit Ihres Programms, indem Sie Unterbefehle hinzufügen, um Ihre Aufgaben in MongoDB zu verwalten.
In diesem Schritt fügen Sie Ihrem CLI-Programm mithilfe des cli
-Pakets einen Unterbefehl hinzu. Am Ende dieses Abschnitts können Sie Ihrer MongoDB-Datenbank eine neue Aufgabe hinzufügen, indem Sie einen neuen add
-Befehl in Ihrem CLI-Programm verwenden.
Öffnen Sie zunächst Ihre main.go
-Datei:
- nano main.go
Importieren Sie als Nächstes die Pakete go.mongodb.org/mongo-driver/bson/primitive
, time
und errors
:
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"
)
. . .
Erstellen Sie dann eine neue Struktur, um eine einzelne Aufgabe in der Datenbank darzustellen, und fügen Sie sie unmittelbar vor der Hauptfunktion
ein:
. . .
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"`
}
. . .
Sie verwenden das primitive
Paket, um den Typ der ID jeder Aufgabe festzulegen, da MongoDB standardmäßig ObjectID
s für das Feld _id
verwendet. Ein weiteres Standardverhalten von MongoDB besteht darin, dass der Feldname in Kleinbuchstaben als Schlüssel für jedes exportierte Feld verwendet wird, wenn es serialisiert wird. Dies kann jedoch mithilfe von bson
struct-Tags geändert werden.
Erstellen Sie als Nächstes eine Funktion, die eine Instanz der Aufgabe
empfängt und in der Datenbank speichert. Fügen Sie dieses Snippet nach der Hauptfunktion
hinzu:
. . .
func createTask(task *Task) error {
_, err := collection.InsertOne(ctx, task)
return err
}
. . .
Die Methode collection.InsertOne()
fügt die bereitgestellte Aufgabe in die Datenbanksammlung ein und gibt die ID des eingefügten Dokuments zurück. Da Sie diese ID nicht benötigen, verwerfen Sie sie, indem Sie sie dem Unterstrichoperator zuweisen.
Der nächste Schritt besteht darin, Ihrem Task-Manager-Programm einen neuen Befehl zum Erstellen neuer Aufgaben hinzuzufügen. Nennen wir ihn add
:
. . .
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)
}
}
Jeder neue Befehl, der Ihrem CLI-Programm hinzugefügt wird, wird im Fenster Befehle
platziert. Jeder besteht aus einem Namen, einer Verwendungsbeschreibung und einer Aktion. Dies ist der Code, der bei der Befehlsausführung ausgeführt wird.
In diesem Code sammeln Sie das erste add
-Argument und verwenden es, um die Texteigenschaft
einer neuen Aufgabeninstanz
festzulegen, während Sie die entsprechenden Standardeinstellungen für die anderen Eigenschaften zuweisen. Die neue Aufgabe wird anschließend an createTask
weitergeleitet, die die Aufgabe in die Datenbank einfügt und nil
zurückgibt, wenn alles gut geht und der Befehl beendet wird.
Speichern und schließen Sie Ihre Datei.
Testen Sie es, indem Sie mit dem Befehl add
einige Aufgaben hinzufügen. Bei Erfolg werden keine Fehler auf Ihrem Bildschirm angezeigt:
- go run main.go add "Learn Go"
- go run main.go add "Read a book"
Nachdem Sie nun erfolgreich Aufgaben hinzufügen können, implementieren wir eine Möglichkeit, alle Aufgaben anzuzeigen, die Sie der Datenbank hinzugefügt haben.
Das Auflisten der Dokumente in einer Sammlung kann mit der Methode collection.Find()
erfolgen, die einen Filter sowie einen Zeiger auf einen Wert erwartet, in den das Ergebnis dekodiert werden kann. Der Rückgabewert ist ein Cursor, der eine Reihe an Dokumenten bereitstellt, die einzeln durchlaufen und dekodiert werden können. Der Cursor wird dann geschlossen, sobald er erschöpft ist.
Öffnen Sie Ihre main.go
-Datei:
- nano main.go
Stellen Sie sicher, dass das Paket bson
importiert wird:
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"
)
. . .
Erstellen Sie dann unmittelbar nach createTask
die folgenden Funktionen:
. . .
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
}
Mit BSON (Binary-coded JSON) werden Dokumente in einer MongoDB-Datenbank dargestellt, und das bson
-Paket hilft uns bei der Arbeit mit BSON-Objekten in Go. Der in der Funktion getAll()
verwendete Typ bson.D
stellt ein BSON-Dokument dar und wird dort verwendet, wo die Reihenfolge der Eigenschaften von Bedeutung ist. Indem Sie bson.D{{}}
als Filter an filterTasks()
übergeben, geben Sie an, dass Sie mit allen Dokumenten in der Sammlung übereinstimmen möchten.
In der Funktion filterTasks()
iterieren Sie über den von der collection.Find()
-Methode zurückgegebenen Cursor und dekodieren jedes Dokument in eine Instanz der Aufgabe
. Jede Aufgabe
wird dann an den zu Beginn der Funktion erstellten Aufgabenbereich angehängt. Sobald der Cursor erschöpft ist, wird er geschlossen und das Aufgabenfenster
zurückgegeben.
Bevor Sie einen Befehl zum Auflisten aller Aufgaben erstellen, erstellen wir eine Hilfsfunktion, die einen Teil der Aufgaben
übernimmt und in die Standardausgabe druckt. Sie verwenden das Paket color
, um die Ausgabe zu färben.
Bevor Sie dieses Paket verwenden können, installieren Sie es mit:
- go get gopkg.in/gookit/color.v1
Sie sehen die folgende Ausgabe:
Outputgo: downloading gopkg.in/gookit/color.v1 v1.1.6
go: gopkg.in/gookit/color.v1 upgrade => v1.1.6
Und importieren Sie sie zusammen mit dem fmt
-Paket in Ihre main.go
-Datei:
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"
)
. . .
Erstellen Sie als Nächstes eine neue printTasks
-Funktion, die Ihrer Hauptfunktion
folgt:
. . .
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)
}
}
}
. . .
Diese printTasks
-Funktion übernimmt eine Reihe von Aufgaben
, durchläuft jede einzelne und druckt sie in der Standardausgabe aus. Dabei wird die grüne Farbe verwendet, um abgeschlossene Aufgaben anzuzeigen, und gelb für unvollständige Aufgaben.
Fahren Sie fort und fügen Sie die folgenden hervorgehobenen Zeilen hinzu, um einen neuen all
-Befehl im Fenster Befehle
zu erstellen. Dieser Befehl druckt alle hinzugefügten Aufgaben in die Standardausgabe:
. . .
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)
}
}
. . .
Der Befehl all
ruft alle in der Datenbank vorhandenen Aufgaben ab und druckt sie in die Standardausgabe. Wenn keine Aufgaben vorhanden sind, wird stattdessen eine Eingabeaufforderung zum Hinzufügen einer neuen Aufgabe gedruckt.
Speichern und schließen Sie Ihre Datei.
Erstellen und führen Sie Ihr Programm mit dem Befehl all
aus:
- go run main.go all
Er wird alle Aufgaben, die Sie bisher hinzugefügt haben, auflisten:
Output1: Learn Go
2: Read a book
Nachdem Sie nun alle Aufgaben in der Datenbank anzeigen können, können Sie im nächsten Schritt die Möglichkeit hinzufügen, eine Aufgabe als erledigt zu markieren.
In diesem Schritt erstellen Sie einen neuen Unterbefehl namens done
, mit dem Sie eine vorhandene Aufgabe in der Datenbank als erledigt markieren können. Um eine Aufgabe als abgeschlossen zu markieren, können Sie die Methode collection.FindOneAndUpdate()
verwenden. Sie ermöglicht es Ihnen, ein Dokument in einer Sammlung zu lokalisieren und einige oder alle seine Eigenschaften zu aktualisieren. Diese Methode erfordert einen Filter zum Auffinden des Dokuments und ein Aktualisierungsdokument zum Beschreiben des Vorgangs. Beide werden mit den Typen bson.D
erstellt.
Beginnen Sie durch Öffnen Ihrer main.go
-Datei:
- nano main.go
Fügen Sie den folgenden Snippet nach Ihrer Funktion filterTasks
ein:
. . .
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)
}
. . .
Die Funktion entspricht dem ersten Dokument, in dem die Texteigenschaft dem Textparameter
entspricht. Das Dokument update
gibt an, dass die Eigenschaft completed
auf true
gesetzt wird. Wenn beim Vorgang FindOneAndUpdate()
ein Fehler auftritt, wird dieser von completeTask()
zurückgegeben. Andernfalls wird nil
zurückgegeben.
Als Nächstes fügen wir Ihrem CLI-Programm einen neuen done
-Befehl hinzu, der eine Aufgabe als erledigt markiert:
. . .
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)
}
}
. . .
Sie verwenden das an den Befehl done
übergebene Argument, um das erste Dokument zu finden, dessen Texteigenschaft
übereinstimmt. Wenn es gefunden wurde, wird die Eigenschaft completed
im Dokument auf true
gesetzt.
Speichern und schließen Sie Ihre Datei.
Führen Sie dann Ihr Programm mit dem Befehl done
aus:
- go run main.go done "Learn Go"
Wenn Sie den Befehl all
erneut verwenden, werden Sie feststellen, dass die als erledigt markierte Aufgabe jetzt grün gedruckt wird.
- go run main.go all
Manchmal möchten Sie nur Aufgaben anzeigen, die noch nicht erledigt sind. Wir fügen diese Eigenschaft als Nächstes hinzu.
In diesem Schritt integrieren Sie einen Code zum Abrufen ausstehender Aufgaben aus der Datenbank mithilfe des MongoDB-Treibers. Ausstehende Aufgaben sind Aufgaben, deren Eigenschaft completed
auf true
gesetzt ist.
Lassen Sie uns eine neue Funktion hinzufügen, die Aufgaben abruft, die noch nicht abgeschlossen sind. Öffnen Sie Ihre main.go
-Datei:
- nano main.go
Fügen Sie dann dieses Snippet nach der Funktion completeTask
hinzu:
. . .
func getPending() ([]*Task, error) {
filter := bson.D{
primitive.E{Key: "completed", Value: false},
}
return filterTasks(filter)
}
. . .
Sie erstellen einen Filter mit den Paketen bson
und primitive
aus dem MongoDB-Treiber, der mit Dokumenten übereinstimmt, deren Eigenschaft completed
auf true
gesetzt ist. Das Segment ausstehender Aufgaben wird dann an den Anrufer zurückgegeben.
Anstatt einen neuen Befehl zum Auflisten ausstehender Aufgaben zu erstellen, sollten Sie ihn zur Standardaktion machen, wenn Sie das Programm ohne Befehle ausführen. Sie können dies tun, indem Sie dem Programm eine Action
-Eigenschaft wie folgt hinzufügen:
. . .
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)
},
},
. . .
Die Action
-Eigenschaft führt eine Standardaktion aus, wenn das Programm ohne Unterbefehle ausgeführt wird. Hier wird eine Logik für das Auflisten ausstehender Aufgaben platziert. Die Funktion getPending()
wird aufgerufen und die resultierenden Aufgaben werden mit printTasks()
in die Standardausgabe gedruckt. Wenn keine ausstehenden Aufgaben vorhanden sind, wird stattdessen eine Eingabeaufforderung angezeigt, in der der Benutzer aufgefordert wird, mit dem Befehl add
eine neue Aufgabe hinzuzufügen.
Speichern und schließen Sie Ihre Datei.
Wenn Sie das Programm jetzt ausführen, ohne Befehle hinzuzufügen, werden alle ausstehenden Aufgaben in der Datenbank aufgelistet:
- go run main.go
Sie sehen die folgende Ausgabe:
Output1: Read a book
Nachdem Sie unvollständige Aufgaben aufgelistet haben, fügen wir einen weiteren Befehl hinzu, mit dem Sie nur abgeschlossene Aufgaben anzeigen können.
In diesem Schritt fügen Sie einen neuen Unterbefehl finished
hinzu, der erledigte Aufgaben aus der Datenbank abruft und auf dem Bildschirm anzeigt. Dies beinhaltet das Filtern und Zurückgeben von Aufgaben, deren Eigenschaft completed
auf true
gesetzt ist.
Öffnen Sie Ihre main.go
-Datei:
- nano main.go
Fügen Sie dann am Ende Ihrer Datei den folgenden Code hinzu:
. . .
func getFinished() ([]*Task, error) {
filter := bson.D{
primitive.E{Key: "completed", Value: true},
}
return filterTasks(filter)
}
. . .
Ähnlich wie bei der Funktion getPending()
haben Sie eine Funktion getFinished()
hinzugefügt, die einen Teil der abgeschlossenen Aufgaben zurückgibt. In diesem Fall hat der Filter die Eigenschaft completed
auf true
gesetzt, sodass nur die Dokumente zurückgegeben werden, die dieser Bedingung entsprechen.
Erstellen Sie als Nächstes einen Befehl finished
, der alle erledigten Aufgaben druckt:
. . .
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)
}
}
. . .
Der Befehl finished
ruft Aufgaben ab, deren Eigenschaft completed
über die hier erstellte Funktion getFinished()
auf true
gesetzt ist. Anschließend werden sie an die Funktion printTasks
übergeben, sodass sie in der Standardausgabe gedruckt werden.
Speichern und schließen Sie Ihre Datei.
Führen Sie den folgenden Befehl aus:
- go run main.go finished
Sie sehen die folgende Ausgabe:
Output1: Learn Go
Im letzten Schritt geben Sie Benutzern die Option, Aufgaben aus der Datenbank zu löschen.
In diesem Schritt fügen Sie einen neuen Unterbefehl delete
hinzu, um Benutzern zu ermöglichen, eine Aufgabe aus der Datenbank zu löschen. Um eine einzelne Aufgabe zu löschen, verwenden Sie die Methode collection.DeleteOne()
vom MongoDB-Treiber. Außerdem stützt er sich auf einen Filter, der dem Dokument entspricht, um das Dokument zu löschen.
Öffnen Sie Ihre main.go
-Datei erneut:
- nano main.go
Fügen Sie diese Funktion deleteTask
hinzu, um Aufgaben direkt nach Ihrer Funktion getFinished
aus der Datenbank zu löschen:
. . .
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
}
. . .
Diese deleteTask
-Methode verwendet ein Zeichenfolgenargument, das das zu löschende Aufgabenelement darstellt. Ein Filter wird so erstellt, dass er mit dem Aufgabenelement übereinstimmt, dessen Texteigenschaft
auf das Zeichenfolgenargument festgelegt ist. Sie übergeben den Filter an die DeleteOne()
-Methode, die dem Element in der Auflistung entspricht, und löschen es.
Sie können die DeletedCount
-Eigenschaft für das Ergebnis der DeleteOne
-Methode überprüfen, um zu bestätigen, ob Dokumente gelöscht wurden. Wenn der Filter nicht mit einem zu löschenden Dokument übereinstimmen kann, ist DeletedCount
Null und Sie können in diesem Fall einen Fehler zurückgeben.
Fügen Sie nun einen neuen Befehl rm
wie hervorgehoben hinzu:
. . .
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)
}
}
. . .
Wie bei allen anderen zuvor hinzugefügten Unterbefehlen verwendet der Befehl rm
sein erstes Argument, um eine Aufgabe in der Datenbank abzugleichen und zu löschen.
Speichern und schließen Sie Ihre Datei.
Sie können ausstehende Aufgaben auflisten, indem Sie Ihr Programm ausführen, ohne Unterbefehle zu übergeben:
- go run main.go
Output1: Read a book
Wenn Sie den Unterbefehl rm
für die Aufgabe „Buch lesen“
ausführen, wird er aus der Datenbank gelöscht:
- go run main.go rm "Read a book"
Wenn Sie alle ausstehenden Aufgaben erneut auflisten, werden Sie feststellen, dass die Aufgabe „Buch lesen“
nicht mehr angezeigt wird, sondern stattdessen eine Aufforderung zum Hinzufügen einer neuen Aufgabe:
- go run main.go
OutputNothing to see here
Run `add 'task'` to add a task
In diesem Schritt haben Sie eine Funktion hinzugefügt, um Aufgaben aus der Datenbank zu löschen.
Sie haben erfolgreich ein Task-Manager-Befehlszeilenprogramm erstellt und dabei die Grundlagen der Verwendung des MongoDB Go-Treibers erlernt.
Lesen Sie unbedingt die vollständige Dokumentation zum MongoDB Go-Treiber bei GoDoc, um mehr über die Funktionen zu erfahren, die die Verwendung des Treibers bietet. Die Dokumentation, in der die Verwendung von Aggregationen oder Transaktionen beschrieben wird, könnte für Sie von besonderem Interesse sein.
Der endgültige Code für dieses Tutorial kann in diesem GitHub repo betrachtet werden.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!