Home  >  Article  >  Backend Development  >  CRUD with Postgres and MongoDB?

CRUD with Postgres and MongoDB?

WBOY
WBOYforward
2024-02-09 14:00:10731browse

使用 Postgres 和 MongoDB 进行 CRUD?

php Editor Xigua will take you through this article to learn how to use Postgres and MongoDB for CRUD operations. Postgres is a relational database, while MongoDB is a document database. CRUD operations refer to the process of creating (Create), reading (Read), updating (Update) and deleting (Delete) data. By combining these two different types of databases, you can choose the most suitable database for data operations based on different needs to improve efficiency and flexibility. Next, let us explore the application of these two databases in CRUD operations!

Question content

I am fairly new to Go and backends, and am participating in the Go internship program. We built a CRUD that connects to a psql database and now I'm told to connect to mongoDB, which we will use for development and PSQL will be used for production. Do I have to create a new handler for mongo from scratch or can I use the same handler and somehow determine the type of database being used and use the logic accordingly? For example, I have a handler for the user registration endpoint:

func (ctrl *UserController) Register(c *gin.Context) {
    var user models.User
    if err := c.BindJSON(&user); err != nil {
        c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
            "error":   true,
            "message": err.Error(),
        })
        return
    }
    err := ctrl.userService.Register(&user)
    if err != nil {
        c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
            "error":   true,
            "message": err.Error(),
        })
        return
    }

    c.JSON(http.StatusCreated, gin.H{
        "message": "successfully created an user",
    })
}

func (svc *UserService) Register(user *models.User) error {
    if svc.userRepo.CheckIfEmailExists(user.Email) {
        return errors.New("user already registered")
    }
    hash, err := svc.generatePasswordHash(user.Password)
    if err != nil {
        return errors.New("err can't register user")
    }

    user.Password = hash

    return svc.userRepo.Insert(user)
}

func (repo *UserRepository) CheckIfEmailExists(mail string) bool {
    var user models.User
    err := repo.dbClient.Debug().Model(models.User{}).Where("email = ?", mail).Find(&user).Error
    return errors.Is(err, gorm.ErrRecordNotFound)
}

func (repo *UserRepository) Insert(user *models.User) error {
    err := repo.dbClient.Debug().Model(models.User{}).Create(user).Error
    if err != nil {
        log.Printf("failed to insert user: %v\n", err)
        return err
    }
    return nil
}

I built the insert, register and CheckIfEmailExists functions for mongo:

func (repo *UserRepository) InsertInMongo(user *models.UserB) error {
    coll := repo.mongoClient.DB.Collection("users")
    _, err := coll.InsertOne(context.TODO(), user)
    if err != nil {
        log.Printf("failed to insert user: %v\n", err)
        return err
    }
    return nil
}

func (svc *UserService) RegisterToMongo(user *models.UserB) error {
    check := svc.userRepo.CheckIfEmailExistsInMongo(user.Email)
    if check {
        return errors.New("user already registered")
    }
    hash, err := svc.generatePasswordHash(user.Password)
    if err != nil {
        return errors.New("err can't register user")
    }
    user.Password = hash
    return svc.userRepo.InsertInMongo(user)
}

func (repo *UserRepository) CheckIfEmailExistsInMongo(email string) bool {
    coll := repo.mongoClient.Collection
    filter := bson.D{{Key: "email", Value: email}}

    count, err := coll.CountDocuments(context.TODO(), filter)
    if err != nil {
        panic(err)
    }
    if count != 0 {
        return true
    }
    return false
}

Solution

You did not provide code on how to create UserService.

Ideally, you should have an interface that looks like this:

type UserRepository interface {
    CheckIfEmailExists(mail string) bool
    Insert(user *models.User) error
    …
}

Then, the UserService should be created like this:

// We use the interface as param
func NewUserService(userRepo UserRepository) UserService {
    return UserService{
        UserRepo: userRepo
    }
}

And you will have two separate repositories, both implementing the UserRepository interface - this means they should have methods with the same name and same signature (parameters, return type) as the interface:

mongo_user_repository.go

Type MongoUserRepo struct {
    …
}

func (repo MongoUserRepo) CheckIfEmailExists(mail string) bool {
  … some mongo logic here
}

func (repo MongoUserRepo) Insert(user *models.User) error {
  … some mongo logic here
}

postgres_user_repository.go

type PostgresUserRepo struct {
    …
}

func (repo PostgresUserRepo) CheckIfEmailExists(mail string) bool {
  … some postgres logic here
}

func (repo PostgresUserRepo) Insert(user *models.User) error {
  … some postgres logic here
}

You can pass any of these depending on the use case, as in the (very bad) example below:

main.go

…

var userService UserService

if os.Getenv(“environment”) == “prod” {
    userService = NewUserService(postgreUserRepo)
} else if os.Getenv(“environment”) == “dev” {
    userService = NewUserService(mongoUserRepo)
}

The above is the detailed content of CRUD with Postgres and MongoDB?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete