В этом коротком примере я покажу вам, как создавать структуры на языке 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»