В этом коротком примере я покажу вам, как создавать структуры на языке Go для использования с MongoDB.
Чтобы продемонстрировать использование структур Golang с MongoDB, в качестве примера я создал простой автоответчик электронной почты. У нас есть контакты, которым мы хотим отправлять электронные письма. Кроме того, у нас есть электронные письма для отправки в определенное время с указанием темы и содержания. Наконец, у нас также есть последовательность, которая связывает контакты с электронными письмами.
Используя структуры Golang, мы сводим к минимуму использование BSON в нашем коде и повышаем удобство использования результатов запросов к базе данных. Эту статью можно рассматривать как продолжение предыдущей статьи под названием Как использовать Go With MongoDB.
Далее я по частям пройдусь по коду небольшой демонстрации.
Импорт соответствующих пакетов
Для начала мы импортируем необходимые пакеты Golang.
Нам нужно импортировать эти библиотеки, чтобы сделать следующее:
context
необходим для создания контекста для операций MongoDB.bson
для сериализации данных, отправляемых на сервер MongoDB.mongo
для подключения к серверу MongoDB и настройки базы данных и коллекций.
Создание структур
Вместо того, чтобы использовать bson
сериализации, как мы делали в предыдущей статье, здесь идея состоит в том, чтобы использовать структуры Golang. Эти структуры должны использовать аннотации bson
для правильной работы.
В приведенном выше фрагменте кода мы видим различные аннотации bson
.
Все эти аннотации следуют одному и тому же шаблону:
bson:"<fieldname>,omitempty"
, где<fieldname>
— фактическое имя поля в базе данных, аomitempty
означает, что поле будет опущено, если не задано значение.
Обратите внимание, что аннотации также находятся между символами ударения вниз и что в них нет пробелов.
Вместо использования omitempty
вы можете использовать другие теги структуры (или вообще не использовать). Подробнее об этом читайте здесь.
В строках 2, 9 и 16 мы устанавливаем тип полей ID
как primitive.ObjectID
. Делая это, мы сообщаем BSON, что эти поля будут действительными MongoDB ObjectIDs
.
Кроме того, поля базы данных _id
всегда будут заполнены, даже если мы будем опускать их при определении экземпляров этих структур (подробнее об этом позже). Сервер MongoDB заполнит эти поля и присвоит им уникальные ObjectIDs
. Мы будем использовать эти ObjectIDs
для обращения к отдельным документам в коллекциях.
В строке 5 мы создаем срез строк. Этот фрагмент будет автоматически преобразован в bson.A
(массив BSON).
В строке 10 вы можете видеть, что также можно использовать поле time.Time
.
В строках 17–18 разместим ссылки на другие документы в базе. Эти ссылки будут списками ObjectIDs
. Здесь я покажу вам два способа сделать это.
Вы можете использовать либо []interface{}
, что является наиболее общим способом, которым вы можете это сделать. Опасность в том, что сюда можно поместить любые значения — включая целые числа, строки и т. д.
Другая возможность — использовать []primitive.ObjectID
. Это особый способ объявления типа. Теперь только ObjectIDs
будет принято. Проблема с этим подходом заключается в том, что позже нам нужно будет написать немного больше кода.
Подключение к MongoDB и настройка базы данных
Первое, что нужно сделать в функции main()
, это подключиться к серверу MongoDB и создать базу данных с коллекциями, которые будут содержать документы.
В строках 1 и 2 мы создаем новый клиент для MongoDB, используя NewClient()
и правильный URI. Обратите внимание, что моя MongoDB работает на localhost
с портом 27017
. Имя пользователя или пароль не установлены, так как это мой тестовый сервер.
В строке 7 мы создаем контекст, используя context.TODO()
. Это самый базовый возможный контекст.
В строке 9 мы разрешаем клиенту подключаться к серверу MongoDB с заданным контекстом.
В строке 14 мы defer
отключаемся от сервера MongoDB. Учитывая, что функция Disconnect()
отложена, она будет выполнена после того, как все остальные операторы в функции main()
будут выполнены.
В строке 16 мы создаем базу данных с именем autoresponder
.
В строках 17–19 мы делаем три коллекции в этой базе данных. Эти коллекции называются contacts
, emails
и sequences
соответственно.
В строках 21–23 мы defer
удаляем коллекции базы данных. Это только для нашего примера, так как я не хочу, чтобы моя база данных заполнялась каждый раз, когда я запускаю код и тестирую новые вещи. Удалите эти строки, если хотите сохранить данные в базе данных.
Вставки в базу данных
Вставка контактов в базу
Давайте создадим несколько фиктивных контактов и вставим их в файл contactsCollection
.
В строках 1–17 мы создаем три контакта (документы в терминологии MongoDB) так же, как мы создаем обычные структуры. Обратите внимание, чем это отличается от использования BSON, как мы делали здесь (прокрутите страницу до половины).
Затем в строке 19 мы вставляем эти контакты в коллекцию contact
, используя InsertMany()
, так как мы хотим вставить сразу несколько документов.
В строке 24 мы получаем идентификаторы вставленных контактов, используя результат insertResult
из строки 19 и свойство InsertedIDs
.
В строке 26 мы создаем срез типа []primitive.ObjectID
с именем contactIDs_
.
В строках 17–29 мы перебираем возвращаемый contactIDs
, приводим каждый элемент к primitive.ObjectID
и добавляем его к contactIDs_
. По-видимому, приведение типов от []interface{}
к []primitive.ObjectID
невозможно; вот почему мы используем цикл for
.
Обратите внимание, что мы не определяли идентификаторы сами. При вставке документов MongoDB автоматически присваивает идентификаторы. Эти идентификаторы сохраняются в поле _id
фактической базы данных, и к ним также можно получить доступ в структуре с помощью свойства ID
.
В строке 31 мы распечатываем фрагмент contactIDs_
, чтобы продемонстрировать, что мы вставили три контакта и что тип правильный.
Мы также можем проверить это с помощью MongoDB Compass.
Вставка писем в базу данных
Теперь давайте также вставим несколько писем в папку emailsCollection
.
Это происходит практически аналогично вставке контактов.
Здесь следует отметить, что в строках 3, 7 и 11 мы используем time.Now()
в качестве значения переменной.
В строке 21 мы извлекаем emailIDs
из возвращаемого результата операции InsertMany()
в строке 16.
Вставка последовательности в базу данных
Наконец, давайте также вставим одну последовательность в файл sequencesCollection
.
В строке 1 мы создаем последовательность, используя структуру Sequence
. В эту структуру мы поместили emailIDs
и contactIDS_
, полученные ранее из результатов вставки.
В строке 3 мы используем InsertOne()
вместо InsertMany()
, которое мы использовали ранее.
Запросы к базе данных
Найти конкретные контакты
В приведенном ниже коде я демонстрирую, как найти контакты с помощью пользовательского фильтра.
В строке 2 мы используем функцию Find()
, чтобы найти все contacts
, удовлетворяющие фильтру bson.M{"tags": "Customer"}
. С помощью этого фильтра мы найдем все контакты, в списке тегов которых есть "Customer"
.
Вы можете, конечно, адаптировать этот фильтр к вашим потребностям. Если вы хотите найти все контакты, вы можете использовать bson.M{}
. Или, если вы хотите найти контакт с адресом электронной почты [email protected]
, вы можете написать bson.M{"email":"[email protected]"}
.
Кроме того, вместо использования формата bson.M
для вашего фильтра вы можете использовать bson.D
. Подробнее об этом здесь.
В строке 7 результаты запроса загружаются в срез []Contact
с именем contacts
с помощью All()
.
В строках 11–15 мы просто выводим некоторые свойства структур Contact
, как и для любой другой структуры.
Таким образом, мы можем максимизировать использование структур Golang и сократить использование BSON до фильтров в запросах.
Найдите последовательность и получите контакты и электронные письма
Ниже мы восстанавливаем последовательность из файла sequencesCollection
. Мы получаем идентификаторы электронной почты и идентификаторы получателей из этой последовательности. Затем эти идентификаторы используются для получения соответствующих электронных писем и контактов.
В строках 10–13 мы используем [0]
, так как была возвращена только одна последовательность.
В строках 17 и 23 мы используем FindOne()
вместе с bson.M{"_id": <id>}
для поиска и фильтрации электронных писем и контактов только для поиска одного конкретного документа на основе его ObjectID
(в <id>
). Поскольку есть только один результат, мы также можем использовать Decode()
вместо All()
для извлечения результатов в структуры Email
и Contact
соответственно.
Полный код
Ниже вы можете найти полный код. Перед выполнением кода убедитесь, что сервер MongoDB работает на mongodb://localhost:27017
, или измените URI.
Рекомендации
«Быстрый старт: Golang и MongoDB — моделирование документов с помощью структур данных Go от MongoDB»
«Работа с BSON по документации MongoDB»
«bson.D против bson.M для поисковых запросов на StackOverflow»