Хорошие новости! Официальный драйвер go для mongoDB вышел в бета-версию. Немного поразмыслив я решил перевести статью с официального сайта mongoDB вместо того, чтобы писать материал самостоятельно. Вот что будет в этом туториале:
- Установка mongo-go-driver
- Соединение с mongoDB с помощью mongo-go-driver
- Использование BSON объектов
- Использование CRUD методов
Исходный код этого руководства находится в [этом GitHub репозитории](https://github.com/tfogo/mongodb-go-tutorial). Для работы с этим руководством требуется установленная MongoDB версии не ниже 3.2 и Golang 1.10 или старше.
Установка mongo-go-driver
Драйвер состоит из нескольких пакетов.
Вы можете установить драйвер с помощью go get:
go get github.com/mongodb/mongo-go-driver
Вывод может содержать в себе следующее предупреждение:
package github.com/mongodb/mongo-go-driver: no Go files in (...)
Это ожидаемый результат.
прим. переводчика: лично я использую модули и там все прекрасно.
Если вы используете в качестве менеджера для управления зависимостсями dep, то вам придется установить основной пакет mongo, также пакет bson и mongo/options:
dep ensure --add github.com/mongodb/mongo-go-driver/mongo
github.com/mongodb/mongo-go-driver/bson
github.com/mongodb/mongo-go-driver/mongo/options
Создание основы
Создайте проект и добавьте в него файл main.go со следующим содержимым:
package main
import (
"context"
"fmt"
"log"
"github.com/mongodb/mongo-go-driver/bson"
"github.com/mongodb/mongo-go-driver/mongo"
"github.com/mongodb/mongo-go-driver/mongo/options"
)
// You will be using this Trainer type later in the program
type Trainer struct {
Name string
Age int
City string
}
func main() {
// Rest of the code will go here
}
В этом коде мы импортируем mongo-go-driver, некоторые стандартные библиотеки и определяем тип Trainer.
Соединение с mongoDB с помощью mongo-go-driver
После того как мы импортировали mongo-go-driver, у нас появилась возможность создать соединение с mongoDB использую функцию mongo.Connect(). У нас есть возможность передать в эту функцию в качестве аргуменов context и стороку содержащую адрес подключения к mongodb. При желании мы также можем передать в качестве третьего аргумента объект options.ClientOptions для тонкой настройки параметров драйвера. В документации подробно описаны доступные парпметры.
Давайте добавим следующий код в тело функции main:
client, err := mongo.Connect(context.TODO(), "mongodb://localhost:27017")
if err != nil {
log.Fatal(err)
}
// Check the connection
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
После успешного соединения с mongoDB мы можем обратиться к коллекции trainers, которая находится в базе с именем test добавив следующий код в конец функции main:
collection := client.Database("test").Collection("trainers")
Рекомендуется держать соединение с mongoDB открытым, чтобы не приходилось открывать и закрывать соединение для каждого запроса. Однако, если приложение больше не требует подключения, оно может быть закрыто с помощю функции client.Disconnect() следующим образом:
err = client.Disconnect(context.TODO())
if err != nil {
log.Fatal(err)
}
fmt.Println("Connection to MongoDB closed.")
Закомментируйте неиспользуемые пакеты bson и mongo/options.
Запустите наш код (go run main.go) чтобы проверить подключение к серверу mongoDB.
Использовение BSON объектов
JSON документы в mongoDB хранятся в двоичном формате, называемом BSON. В отличие от других баз данных в которых JSON данные хранятся в виде строк и чисел, кодировка BSON добавляет новые типы, такие как int, long, date, float и decimal128.
Это значительно упрощает обработку, сортировку и сравнение данных приложениями. Драйвер Go имеет два семейства типов для представления данных BSON: Типы D и типы RAW.
Семейство D состоит из четырех типов:
- D: документ BSON. Этот тип следует использовать в ситуациях, когда порядок имеет значение, например, команды MongoDB.
- M: Неупорядоченный словарь(ассоциативный массив, map). Он такой же, как D, за исключением того, что он не сохраняет порядок.
- A: массив BSON.
- E: одиночный элемент внутри D.
Вот пример фильтра, построенного с использованием D-типов, который производит поиск документов, в которых поле name соответствует значениям Alice или Bob:
Семейство типов Raw используется для проверки среза байтов. Вы можете извлечь одиночные элементы из типов Raw, используя Lookup().
Это может быть полезно когда необходимо избавиться от лишней нагрузки при конвертировании BSON в иной тип. В этом туториале будет использоваться только семейство типов D.
Использование CRUD методов
После успешного соединения с базой данных, мы можем начать добавлять и изменять данные в нашей коллекции. Тип Collection содержит в себе методы позволяющие отправлять запросы в базу данных.
Вставка (создание) документов
Для начала необходимо создать несколько новых структур Trainer для вставки в базу данных:
ash := Trainer{"Ash", 10, "Pallet Town"}
misty := Trainer{"Misty", 10, "Cerulean City"}
brock := Trainer{"Brock", 15, "Pewter City"}
Для того чтобы всавить одиночный документ следует использовать метод collection.InsertOne():
insertResult, err := collection.InsertOne(context.TODO(), ash)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted a single document: ", insertResult.InsertedID)
Для вставки нескольких документов одновременно существут метод collection.InsertMany():
trainers := []interface{}{misty, brock}
insertManyResult, err := collection.InsertMany(context.TODO(), trainers)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted multiple documents: ", insertManyResult.InsertedIDs)
Обновление документов
Метод collection.UpdateOne() позволяет обновить один документ. Требуется создать фильтр для поиска документа в базе данных и документ для операции обновления. Вы можете создать их, используя типы bson.D:
filter := bson.D{{"name", "Ash"}}
update := bson.D{
{"$inc", bson.D{
{"age", 1},
}},
}
Следующий код найдет документ, в котором поле name совпадает со значением Ash и увеличит значение age на 1.
updateResult, err := collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Matched %v documents and updated %v documents.n", updateResult.MatchedCount, updateResult.ModifiedCount)
Поиск документов
Чтобы найти документ, вам понадобится фильтр, а также указатель на переменную, в которую может быть декодирован результат.
Чтобы найти один документ, используйте collection.FindOne(). Этот метод возвращает одно значение, которое можно декодировать в переменную.
Мы будем использовать ту же переменную фильтра, которую использовали в запросе на обновление.
// create a value into which the result can be decoded
var result Trainer
err = collection.FindOne(context.TODO(), filter).Decode(&result)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found a single document: %+vn", result)
Чтобы найти несколько документов, используйте collection.Find().
Этот метод возвращает Cursor. Cursor предоставляет поток документов, с помощью которого можно перебирать и декодировать по одному документу за раз.
Когда документы в Cursor исчерпываются, следует закрыть Cursor. Также Cursor можно тонко настроить использую пакет options.
В нашем примере, мы устанавливаем лимит на выдачу двух документов.
// Pass these options to the Find method
options := options.Find()
options.SetLimit(2)
// Here's an array in which you can store the decoded documents
var results []*Trainer
// Passing nil as the filter matches all documents in the collection
cur, err := collection.Find(context.TODO(), nil, options)
if err != nil {
log.Fatal(err)
}
// Finding multiple documents returns a cursor
// Iterating through the cursor allows us to decode documents one at a time
for cur.Next(context.TODO()) {
// create a value into which the single document can be decoded
var elem Trainer
err := cur.Decode(&elem)
if err != nil {
log.Fatal(err)
}
results = append(results, &elem)
}
if err := cur.Err(); err != nil {
log.Fatal(err)
}
// Close the cursor once finished
cur.Close(context.TODO())
fmt.Printf("Found multiple documents (array of pointers): %+vn", results)
Удаление документов
Вы можете удалить документы, используя collection.DeleteOne() или collection.DeleteMany().
Мы передаем nil в качестве аргумента фильтра, который будет соответствовать всем документам в коллекции. Также можно использовать collection.Drop() для удаления всей коллекции.
deleteResult, err := collection.DeleteMany(context.TODO(), nil)
if err := cur.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted %v documents in the trainers collectionn", deleteResult.DeletedCount)
Далнейшие шаги
→ Финальный код этого туториала находится в репозитории GitHub
→ Документация к драйверу достпна в GoDoc
Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь с нами в группе Google mongo-go-driver.
Пожалуйста, отправляйте отчеты об ошибках в MongoDB JIRA.
Мы будем рады получить ваши отзывы о Go Driver.
Автор: pocoZ