Я использую MongoDB для разработки системы продажи билетов с использованием Go. У меня есть две сущности: пользователи и билеты, каждая из которых имеет свой уникальный идентификатор. Я хотел бы иметь возможность различать два типа идентификаторов, чтобы функции могли запрашивать получение либо UserID, либо TicketID.
Я попытался определить два новых типа, базовым типом которых является primitive.ObjectID
:
type UserID primitive.ObjectID
type TicketID primitive.ObjectID
Затем я использовал этот тип в своей пользовательской структуре:
type User struct {
ID UserID `json:"id" bson:"_id"`
}
Наконец, я попытался получить массив всех пользователей в базе данных, используя этот код:
func (coll *mongo.Collection) GetAllUsers(ctx context.Context) ([]User, error) {
cursor, err := coll.Find(ctx, bson.D{})
if err != nil {
return []User{}, err
}
users := []User{}
err = cursor.All(ctx, &users)
if err != nil {
return []User{}, err
}
return users, nil
}
Однако попытка сделать это приводит к следующей ошибке:
cannot decode ObjectID into an array
Как я могу добиться различия между UserID и TicketID, избежав при этом этой ошибки?
Для декодирования результатов я использую следующую функцию: func (coll *mongo.Collection) GetAllUsers(ctx context.Context) ([]User, error) { cursor, err := coll.Find(ctx, bson.D{}) if err != nil { return []User{}, err } users := []User{} err = cursor.All(ctx, &users) if err != nil { return []User{}, err } return users, nil }
@Louis Поместите код и информацию в свой комментарий выше в свой вопрос.
Определение типа создает новый, отдельный тип и удаляет его методы:
type UserID primitive.ObjectID
type TicketID primitive.ObjectID
После этого пакеты mongo
и bson
больше не будут распознавать UserID
и TicketID
как ObjectID
(так же, как их базовый массив байтов) и не будут знать, как демаршалировать в них MongoDB ObjectID.
Вместо этого используйте псевдонимы типов, тогда в вашем коде будут разные имена, а поскольку псевдоним типа не создает новый тип (просто привязывает другой идентификатор к тому же типу), он будет работать так, как вы ожидаете:
type UserID = primitive.ObjectID
type TicketID = primitive.ObjectID
Обратите внимание, что после приведенных выше объявлений типов UserID
, TicketID
и primitive.ObjectID
будут одного и того же, идентичного типа, поэтому не стоит ожидать, что вы сможете различать их по типу.
Помешает ли это разработчику передать TicketID в функцию, ожидающую UserID?
@ Луи Нет, это не так. Но MongoDB не хранит ваш тип Go, а хранит только тип ObjectId
, который использует внутри. Так что на самом деле нет никакого смысла/инструмента для борьбы с этим.
Структура пользователя и теги выглядят правильно. Как вы расшифровываете результат? Это должно выглядеть примерно так:
go func GetUserByID(ctx context.Context, id UserID) (*User, error) { var user User coll := mongoClient.Database("my-db").Collection("my-collection") result := coll.FindOne(ctx, bson.M{"_id": id}) if err := result.Decode(&user); err != nil { return &user, err } return &user, nil }