2
\$\begingroup\$

I'm using fiber and mongodb. Field "field" is needed to obtain certain data to unload the load on the database. If field "field" is empty, then needs to output all the data from the database to make work easier to frontend. I don't like this crutch. Is there a much better solution?

func GetUserById(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var userId = c.Params("userId")
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    // Creates options for search.
    opts, err := search.GetOneOptions(c, models.UserModel{})
    if err != nil {
        return responses.Response(c, http.StatusBadRequest, err.Error())
    }

    if c.Query("field") != "" {
        var user models.UserModelOmitempty

        err = usersCollection.FindOne(ctx, bson.M{"_id": objId}, opts).Decode(&user)
        if err != nil {
            return responses.Response(c, http.StatusBadRequest, "user not found")
        }

        return responses.ResponseWithData(c, http.StatusOK, "success", user)
    } else {
        var user models.UserModel

        err = usersCollection.FindOne(ctx, bson.M{"_id": objId}, opts).Decode(&user)
        if err != nil {
            return responses.Response(c, http.StatusBadRequest, "user not found")
        }

        return responses.ResponseWithData(c, http.StatusOK, "success", user)
    }

}

models.UserModel

type UserModel struct {
    Id               primitive.ObjectID `json:"id" bson:"_id" query:"string"`
    Name             string             `json:"name" bson:"name" validate:"required" query:"string"`
    Email            string             `json:"email" bson:"email" validate:"required" query:"string"`
    Password         string             `json:"-" bson:"password" validate:"required"`
    CreatedAt        int64              `json:"createdAt" bson:"createdAt" query:"int"`
    Rights           string             `json:"rights" bson:"rights" query:"string"`
    PhotoUrl         string             `json:"photoUrl" bson:"photoUrl"`
    Sex              string             `json:"sex" bson:"sex" query:"string"`
    BirthDate        int64              `json:"birthDate" bson:"birthDate" query:"int"`
    Country          string             `json:"country" bson:"country" query:"string"`
    EmailSubscribe   bool               `json:"emailSubscribe" bson:"emailSubscribe" query:"bool"`
    AccountConfirmed bool               `json:"accountConfirmed" bson:"accountConfirmed" query:"bool"`
}

models.UserModelOmitempty

type UserModelOmitempty struct {
    Id               primitive.ObjectID `json:"id" bson:"_id" query:"string"`
    Name             string             `json:"name,omitempty" bson:"name" validate:"required" query:"string"`
    Email            string             `json:"email,omitempty" bson:"email" validate:"required" query:"string"`
    Password         string             `json:"-" bson:"password" validate:"required"`
    CreatedAt        int64              `json:"createdAt,omitempty" bson:"createdAt" query:"int"`
    Rights           string             `json:"rights,omitempty" bson:"rights" query:"string"`
    PhotoUrl         string             `json:"photoUrl,omitempty" bson:"photoUrl"`
    Sex              string             `json:"sex,omitempty" bson:"sex" query:"string"`
    BirthDate        int64              `json:"birthDate,omitempty" bson:"birthDate" query:"int"`
    Country          string             `json:"country,omitempty" bson:"country" query:"string"`
    EmailSubscribe   bool               `json:"emailSubscribe,omitempty" bson:"emailSubscribe" query:"bool"`
    AccountConfirmed bool               `json:"accountConfirmed,omitempty" bson:"accountConfirmed" query:"bool"`
}

Result in postman: without field

with field

\$\endgroup\$
2
  • \$\begingroup\$ I'm assuming this snippet is part of a function or method. Where is the rest of it? I see code duplication so we can probably improve it, but a good review requires more context. \$\endgroup\$
    – Mast
    Jun 26 at 9:00
  • 1
    \$\begingroup\$ @Mast Thanks for the comment, I added more data. \$\endgroup\$
    – Boro8ey
    Jun 26 at 9:23

2 Answers 2

4
\$\begingroup\$

Since the types seem to be identical except for the JSON tags, you could use either models.UserModel or models.UserModelOmitempty for most of code, until the point where serialization comes into play, which will be when you call responses.Response(...) and then convert to the correct type:

var user 
err = usersCollection.FindOne(ctx, bson.M{"_id": objId}, opts).Decode(&user)
if err != nil {
    return responses.Response(c, http.StatusBadRequest, "user not found")
}
if c.Query("field") != "" {
    // No field specified, so omitting empty fields
    return responses.ResponseWithData(c, http.StatusOK, "success", models.UserModelOmitempty(user))
}
return responses.ResponseWithData(c, http.StatusOK, "success", user)
\$\endgroup\$
0
\$\begingroup\$

Thanks @muru for giving me the idea. The result here:

Models.

type UserModel struct {
    Id               primitive.ObjectID `json:"id" bson:"_id" query:"string"`
    Name             string             `json:"name" bson:"name" validate:"required" query:"string"`
    Email            string             `json:"email" bson:"email" validate:"required" query:"string"`
    Password         string             `json:"-" bson:"password" validate:"required"`
    CreatedAt        *time.Time         `json:"createdAt" bson:"createdAt" query:"date"`
    Rights           string             `json:"rights" bson:"rights" query:"string"`
    PhotoUrl         string             `json:"photoUrl" bson:"photoUrl"`
    Sex              string             `json:"sex" bson:"sex" query:"string"`
    BirthDate        *time.Time         `json:"birthDate" bson:"birthDate" query:"date"`
    Country          string             `json:"country" bson:"country" query:"string"`
    EmailSubscribe   bool               `json:"emailSubscribe" bson:"emailSubscribe" query:"bool"`
    AccountConfirmed bool               `json:"accountConfirmed" bson:"accountConfirmed" query:"bool"`
}
type UserModelOmitempty struct {
    Id               primitive.ObjectID `json:"id" bson:"_id"`
    Name             string             `json:"name,omitempty"`
    Email            string             `json:"email,omitempty"`
    Password         string             `json:"-" bson:"password"`
    CreatedAt        *time.Time         `json:"createdAt,omitempty"`
    Rights           string             `json:"rights,omitempty"`
    PhotoUrl         string             `json:"photoUrl,omitempty"`
    Sex              string             `json:"sex,omitempty"`
    BirthDate        *time.Time         `json:"birthDate,omitempty"`
    Country          string             `json:"country,omitempty"`
    EmailSubscribe   bool               `json:"emailSubscribe,omitempty"`
    AccountConfirmed bool               `json:"accountConfirmed,omitempty"`
}

func (u *UserModel) ConvertToOmitempty() interface{} {
    return UserModelOmitempty{
        Id:               u.Id,
        Name:             u.Name,
        Email:            u.Email,
        CreatedAt:        u.CreatedAt,
        Rights:           u.Rights,
        PhotoUrl:         u.PhotoUrl,
        Sex:              u.Sex,
        BirthDate:        u.BirthDate,
        Country:          u.Country,
        EmailSubscribe:   u.EmailSubscribe,
        AccountConfirmed: u.AccountConfirmed,
    }
}

Controller.

func GetUserById(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var userId = c.Params("userId")
    var user models.UserModel
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    // Creates options for search.
    opts, err := search.GetOneOptions(c, models.UserModel{})
    if err != nil {
        return responses.Response(c, http.StatusBadRequest, err.Error())
    }

    err = usersCollection.FindOne(ctx, bson.M{"_id": objId}, opts).Decode(&user)
    if err != nil {
        return responses.Response(c, http.StatusBadRequest, "user not found")
    }

    if c.Query("field") != "" {
        return responses.ResponseWithData(c, http.StatusOK, "success", user.ConvertToOmitempty())
    }

    return responses.ResponseWithData(c, http.StatusOK, "success", user)
}

```
\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.