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

asked Jun 26, 2022 at 8:40
\$\endgroup\$
1
  • \$\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\$ Commented Jun 26, 2022 at 9:00

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)
answered Jun 26, 2022 at 11:59
\$\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)
}
```
answered Jun 26, 2022 at 12:36
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Rather than post updated code as an answer, you should post a follow up question with a link back to this question. You should also read What to do when someone answers my question. \$\endgroup\$ Commented Jun 26, 2022 at 13:49

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.