【发布时间】:2019-12-02 17:11:20
【问题描述】:
我编写了一个连接到 google firestore 作为后端的 rest api。我有一个用户集合,并希望确保每个用户文档都有一个唯一的用户名。我的第一种方法是在数据库中查询具有相同用户名的匹配文档,如果找到,则用户必须选择另一个(在注册时)。
这是我对应的代码(golang)
func (service *Service) CreateUser(ctx context.Context, user domains.User) (domains.User, error) {
var err error
err = domains.ValidateNewUser(user)
if err != nil {
return user, err
}
// Check if email already exists
unique, err := service.CheckEmailUniqueness(ctx, user.Email)
if err != nil {
return user, err
} else if !unique {
return user, ErrEmailExists
}
// Check if user already exists
unique, err = service.CheckUsernameUniqueness(ctx, user.Username)
if err != nil {
return user, err
} else if !unique {
return user, ErrUsernameExists
}
docRef, _, err := service.Client.Collection("users").Add(ctx, user)
if err != nil {
return user, ErrCreatingUser
}
user.UserID = docRef.ID
return user, nil
}
func (service *Service) CheckUsernameUniqueness(ctx context.Context, username string) (bool, error) {
iter := service.Client.Collection("users").Where("username", "==", username).Documents(ctx)
usernameExists := false
for {
_, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
return false, err
}
usernameExists = true
break
}
return !usernameExists, nil
}
但是在这种情况下如何防止竞争条件?就像当 2 个不同的用户想要使用相同的用户名并且他们的请求由我的休息服务器的两个不同实例处理时一样。总的来说,我对 firestore 和 NoSQL 非常缺乏经验,所以如果我不明白任何重要的内容,请见谅。
【问题讨论】:
-
查看 Firestore 中事务的使用,以确保一组操作是原子的。
-
据我了解,只有在您想防止同时写入同一个文档时,事务才有帮助。但在我的用例中并非如此。我想创建唯一的用户(因此不同的文档具有唯一的用户名)。
-
事务可用于读写操作。在事务中,您可以读取文档以确保它在创建之前不存在。从这个意义上说,用户可以“保留”他们的用户名,而不必担心另一个用户在事务之外声明它(只要他们都使用事务来保护访问)。
-
酷!很高兴知道,谢谢
标签: google-app-engine google-cloud-platform google-cloud-firestore