Mongo-go-driver получает идентификатор объекта из результата вставки

После использования InsertOne чтобы создать новый документ, когда я возвращаю результат, я получаю массив чисел, а не ObjectID, В БД идентификатор генерируется нормально.

type User struct {
  ID       string
  Email    string
  Username string
  Password string
}

var db = ...

// UserStore creates user
func UserStore(c echo.Context) (err error) {

  coll := db.Collection("users")

  u := new(User)
  if err = c.Bind(u); err != nil {
    return c.JSON(http.StatusInternalServerError, err)
  }

  result, err := coll.InsertOne(
    context.Background(),
    bson.NewDocument(
        bson.EC.String("email", u.Email),
        bson.EC.String("username", u.Username),
        bson.EC.String("password", u.Password),
    ),
  )
  if err != nil {
    return c.JSON(http.StatusInternalServerError, err)
  }

  return c.JSON(http.StatusCreated, result)
}

Это возвращает что-то вроде InsertedID: [90, 217, 85, 109, 184, 249, 162, 204, 249, 103, 214, 121] вместо нормального ObjectID, Как я могу вернуть фактический ObjectID из недавно вставленного документа?

1 ответ

Решение

Успешный Collection.InsertOne() вернет результат типа mongo.InsertOneResult, которая является структурой, заключающей в себе идентификатор вновь вставленного документа:

type InsertOneResult struct {
    // The identifier that was inserted.
    InsertedID interface{}
}

Официальный драйвер MongoDB Go использует objectid.ObjectID тип для представления MongoDB ObjectIds. Этот тип представляет собой простой байтовый массив:

type ObjectID [12]byte

InsertOneResult.InsertedID будет держать динамический тип objectid.ObjectID, objectid.ObjectID Тип не определяет пользовательский метод маршалинга JSON (не реализует json.Marshaler), что означает, что при преобразовании результата в JSON будут использоваться правила маршалинга по умолчанию, которые для байтового массива (не для слайса) - это то, что вы видите: десятичное представление байтов ObjectID.

Вы не должны конвертировать значение типа InsertOneResult в JSON, как это (точнее objectid.ObjectID само по себе) не "JSON-friendly" (по крайней мере, в текущей версии).

Вместо этого создайте / оберните свой собственный тип, где вы определяете, как вы хотите, чтобы результат выглядел в JSON, например:

if oid, ok := result.InsertedID.(objectid.ObjectID); ok {
    return c.JSON(http.StatusCreated, map[string]interface{}{
        "id": oid.String(),
    })
} else {
    // Not objectid.ObjectID, do what you want
}

Приведенный выше код приведет к ответу JSON, например:

{"id":"ObjectID(\"5ad9a913478c26d220afb681\")"}

Или, если вы просто хотите шестнадцатеричное представление:

if oid, ok := result.InsertedID.(objectid.ObjectID); ok {
    return c.JSON(http.StatusCreated, map[string]interface{}{
        "id": oid.Hex(),
    })
}

Который будет:

{"id":"5ad9a913478c26d220afb681"}
Другие вопросы по тегам