如何在 Spring 中使用 MongoDB 强制执行唯一字段

dbr*_*ter 6 java unique-index mongodb spring-boot

我有一个 pojo,其中有两个字段需要唯一,即 id 和电子邮件。所以我将@Indexed(unique = true)注释添加到必要的字段中,如下所示

public class User {
    @Id
    @Indexed(unique = true)
    private String id;
    @Indexed(unique = true)
    private String email;
    private int money;
Run Code Online (Sandbox Code Playgroud)

然后我测试了一下,并没有强制执行。所以我用谷歌搜索,在这里找到了以前的答案 - Spring Data: Unique field in MongoDB document并随后删除了该集合,添加spring.data.mongodb.auto-index-creation=true到我的 application.properties 文件中并再次尝试。

但是,唯一字段仍然没有强制执行!我看到有另一个答案使用ensureIndex(),但它也有一个从未得到答复的很棒的评论 -Why do we need to use the annotation if all the work is done on mongoTemplate?

因此,由于问题已经足够老了,显然唯一有效的答案已被贬值(新方法是使用createIndex()),我认为是时候推出新版本了。是否可以要求 mongo 集合中的列在 Spring Boot 中是唯一的?

小智 2

看来该问题已在当前最新的 Spring Boot Data MongoDB 版本(v3.0.4)中修复。

我使用 Spring Boot v3.0.4 和 Java 17/Kotlin 在我自己的个人项目上对此进行了测试,我的文档类最终如下所示:

@Document
class User(@Indexed(unique = true) var username: String) {

    @Id
    var id: String? = null

    var name: String? = null

    var surname: String? = null
}
Run Code Online (Sandbox Code Playgroud)

重要提示:我确实需要添加spring.data.mongodb.auto-index-creation=true到我的 application.properties 文件中,只有在执行此操作并将集合删除到 MongoDB 上之后,我才在我的用户 API 上实际强制执行了该字段。

就我而言,在添加所有上述配置(@Indexed(unique=true)和)之后,在尝试插入与现有用户相同的spring.data.mongodb.auto-index-creation=true用户时,我开始收到以下错误:username

curl -v --location 'http://localhost:9000/user' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "username": "testuser1",
    "name": "Test",
    "surname": "User 1"
}'
*   Trying 127.0.0.1:9000...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> POST /user HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.81.0
> Accept: */*
> Authorization: Bearer <token>
> Content-Type: application/json
> Content-Length: 76
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 409 
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Tue, 14 Mar 2023 18:48:08 GMT
< 
* Connection #0 to host localhost left intact
{"cause":{"cause":null,"message":"Write operation error on server localhost:27017. Write error: WriteError{code=11000, message='E11000 duplicate key error collection: test.user index: username dup key: { username: \"testuser1\" }', details={}}."},"message":"Write operation error on server localhost:27017. Write error: WriteError{code=11000, message='E11000 duplicate key error collection: test.user index: username dup key: { username: \"testuser1\" }', details={}}."}

Run Code Online (Sandbox Code Playgroud)

检查数据库记录发现,它确实限制并停止了写入操作。

本次测试使用的其他版本:

kotlin("jvm") - 1.7.22
kotlin("plugin.spring") - "1.7.22"

MongoDB - 4.4.10
Ubuntu (host) - 22.04
Run Code Online (Sandbox Code Playgroud)