文档自动过期删除功能异常求助:30分钟删除需求遇阻,@Indexed(expireAfterSeconds)配置后未生效
Hey there! Let's walk through why your auto-expiration setup isn't working as expected, and fix it step by step.
First, let's clarify a few key details about MongoDB TTL indexes—they have specific behaviors that are easy to miss:
1. Fix Your Expiration Time Configuration
Looking at your code, you set expireAfterSeconds=3600 (which equals 1 hour), but you mentioned wanting documents to delete after 30 minutes. That's a quick adjustment: change the value to 1800 (30 * 60) if that's your intended expiration window.
Even with the correct value, don't expect instant deletion—MongoDB runs the TTL cleanup task every 60 seconds by default, so there can be up to a 1-minute delay after the document's actual expiration time.
2. Verify the TTL Index Was Created in MongoDB
Sometimes Spring Data might not apply the index correctly. Let's confirm it exists:
- Connect to your MongoDB instance via the shell
- Run this command for your collection (assuming your collection name is
confirmationToken, the default for your entity):db.confirmationToken.getIndexes()
Look for an index on the createdDate field with the expireAfterSeconds value you set. If it's missing:
- Ensure auto-index creation is enabled in your Spring Boot properties:
spring.data.mongodb.auto-index-creation=true(note: newer Spring Boot versions require this explicit setting) - Re-save existing documents—TTL indexes only apply to documents saved after the index is created. Old documents won't get the TTL behavior unless you update their
createdDatefield.
3. Ensure createdDate is a Valid BSON Date Type
MongoDB only processes TTL indexes on fields stored as BSON Date types. Double-check that your createdDate is saved correctly:
db.confirmationToken.findOne({tokenid: "your-test-token-id"}).createdDate
The output should look like ISODate("2024-05-20T12:34:56.789Z"), not a string like "2024-05-20...". Your code sets createdDate = new Date(); which should work, but it's worth verifying directly in the database.
4. Simplify Annotations (Optional)
Your @Field annotation on createdDate isn't necessary here unless you're mapping to a different field name in the database. You can safely remove it. The name parameter in @Indexed is also optional—omitting it will let MongoDB use the field name as the index name, which is perfectly fine.
5. Rule Out Edge Cases
- TTL indexes don't work on capped collections: Make sure your
confirmationTokencollection isn't capped (you'd have to explicitly create it as capped, so this is unlikely unless you did it intentionally) - If you're using a custom collection name (via
@Document(collection = "custom-name")), confirm you're checking the correct collection in the MongoDB shell
Example Corrected Code (30-Minute Expiration)
public class ConfirmationToken { @Id private String tokenid; private String confirmationToken; @Indexed(expireAfterSeconds = 1800) // 30 minutes = 1800 seconds private Date createdDate; private Entity user; public ConfirmationToken() { } public ConfirmationToken(Entity user) { this.user = user; createdDate = new Date(); confirmationToken = UUID.randomUUID().toString(); } // Getters and Setters }
Give these steps a try, and let me know if you still run into issues!
内容的提问来源于stack exchange,提问作者user16071339

