diff --git a/.env.example b/.env.example index f04f2ed..a8fa09e 100644 --- a/.env.example +++ b/.env.example @@ -2,10 +2,7 @@ # cp .env.example .env # MongoDB configuration -MONGODB_CONNECTION_STRING=mongodb://localhost:27017 -MONGODB_USERNAME=your_mongodb_username -MONGODB_PASSWORD=your_mongodb_password -MONGODB_DATABASE_NAME=store-scraper-bot +MONGODB_CONNECTION_STRING=mongodb://localhost:27017/store-scraper-bot # Telegram Bot configuration TELEGRAM_BOT_TOKEN=your_telegram_bot_token diff --git a/build.gradle.kts b/build.gradle.kts index f8658f6..b0f38b2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,13 +22,13 @@ configurations { dependencies { annotationProcessor("org.projectlombok:lombok:1.18.36") - implementation("org.mongodb:mongodb-driver-sync:5.2.1") implementation("com.fasterxml.jackson.core:jackson-databind:2.18.2") implementation("com.google.code.gson:gson:2.11.0") implementation("com.google.guava:guava:33.4.0-jre") implementation("org.apache.commons:commons-math3:3.6.1") implementation("org.apache.logging.log4j:log4j-core:2.24.3") implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3") + implementation("org.mongodb:mongodb-driver-sync:5.2.1") implementation("org.telegram:telegrambots-client:8.0.0") implementation("org.telegram:telegrambots-extensions:8.0.0") implementation("org.telegram:telegrambots-longpolling:8.0.0") diff --git a/compose.dev.couchbase.yml b/compose.dev.couchbase.yml deleted file mode 100644 index 4a2e505..0000000 --- a/compose.dev.couchbase.yml +++ /dev/null @@ -1,18 +0,0 @@ -services: - couchbase: - image: couchbase:community-7.6.2 - env_file: - - .env - ports: - - "8091-8097:8091-8097" - - "9123:9123" - - "11207:11207" - - "11210:11210" - - "11280:11280" - - "18091-18097:18091-18097" - volumes: - - couchbase_data:/opt/couchbase/var - restart: unless-stopped - -volumes: - couchbase_data: diff --git a/compose.dev.mongodb.yml b/compose.dev.yml similarity index 100% rename from compose.dev.mongodb.yml rename to compose.dev.yml diff --git a/src/main/java/com/miti99/storescraperbot/constant/Constant.java b/src/main/java/com/miti99/storescraperbot/constant/Constant.java index f768256..0a7ebdc 100644 --- a/src/main/java/com/miti99/storescraperbot/constant/Constant.java +++ b/src/main/java/com/miti99/storescraperbot/constant/Constant.java @@ -15,4 +15,6 @@ public class Constant { public static final ZoneId VIETNAM_ZONE_ID = ZoneId.of(VIETNAM_ZONE_ID_STRING); public static final long SECONDS_PER_DAY = ChronoUnit.DAYS.getDuration().getSeconds(); public static final Set WEEKENDS = Set.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY); + + public static final String DEFAULT_DATABASE_NAME = "store-scraper-bot"; } diff --git a/src/main/java/com/miti99/storescraperbot/env/Environment.java b/src/main/java/com/miti99/storescraperbot/env/Environment.java index 1fbe2dc..2c89822 100644 --- a/src/main/java/com/miti99/storescraperbot/env/Environment.java +++ b/src/main/java/com/miti99/storescraperbot/env/Environment.java @@ -9,11 +9,7 @@ import java.util.Optional; import java.util.stream.Collectors; public class Environment { - public static final String MONGODB_CONNECTION_STRING = - System.getenv("MONGODB_CONNECTION_STRING"); - public static final String MONGODB_USERNAME = System.getenv("MONGODB_USERNAME"); - public static final String MONGODB_PASSWORD = System.getenv("MONGODB_PASSWORD"); - public static final String MONGODB_DATABASE_NAME = System.getenv("MONGODB_DATABASE_NAME"); + public static final String MONGODB_CONNECTION_STRING = System.getenv("MONGODB_CONNECTION_STRING"); public static final String TELEGRAM_BOT_TOKEN = System.getenv("TELEGRAM_BOT_TOKEN"); public static final String TELEGRAM_BOT_USERNAME = System.getenv("TELEGRAM_BOT_USERNAME"); diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java index dc286f4..60827c8 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java @@ -3,13 +3,11 @@ package com.miti99.storescraperbot.repository; import static com.miti99.storescraperbot.repository.AbstractSingletonRepository.COMMON_COLLECTION_NAME; import com.google.common.base.CaseFormat; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoDatabase; -import com.mongodb.client.model.Filters; -import com.mongodb.client.model.ReplaceOptions; -import com.miti99.storescraperbot.env.Environment; import com.miti99.storescraperbot.model.AbstractModel; import com.miti99.storescraperbot.util.MongoDBUtil; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.ReplaceOptions; import java.lang.reflect.ParameterizedType; import lombok.extern.log4j.Log4j2; @@ -58,13 +56,6 @@ public abstract class AbstractRepository> { return MongoDBUtil.DATABASE.getCollection(collectionName, classV); } - /** - * @return expire seconds. 0 mean never expire. - */ - protected long getExpireSeconds() { - return 0; - } - protected void init(K key) { try { if (exist(key)) { @@ -85,12 +76,8 @@ public abstract class AbstractRepository> { protected void save(K key, V data) { var databaseKey = getDatabaseKey(key); try { - var replaceOptions = new ReplaceOptions(); - if (getExpireSeconds() > 0) { - // MongoDB TTL indexes need to be created at the collection level - // For now, we'll just save without TTL and handle TTL through indexes - } - collection().replaceOne(Filters.eq("_id", databaseKey), data, replaceOptions); + collection() + .replaceOne(Filters.eq("_id", databaseKey), data, new ReplaceOptions().upsert(true)); } catch (Exception e) { log.error("save error - key {}, databaseKey {}", key, databaseKey, e); } diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java index 94877b6..2b2d9df 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java @@ -5,8 +5,7 @@ import lombok.extern.log4j.Log4j2; /** * Repository chỉ chứa 1 key duy nhất, public các method liên quan nhưng không cho truyền params - * vào. Các repository loại này được lưu trong 1 collection duy nhất là "common" (do MongoDB không - * giới hạn số lượng collection nên gom nhóm các repository loại này lại để quản lý tập trung) + * vào. Các repository loại này được lưu trong 1 collection duy nhất là "common" */ @Log4j2 public abstract class AbstractSingletonRepository> diff --git a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java index 4a9c897..4f703a8 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java @@ -1,19 +1,7 @@ package com.miti99.storescraperbot.repository; -import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.AppleApp; -import com.miti99.storescraperbot.util.MongoDBUtil; public class AppleAppRepository extends AbstractCollectionRepository { public static final AppleAppRepository INSTANCE = new AppleAppRepository(); - - static { - // Create TTL index for cached data - MongoDBUtil.createTTLIndexIfNotExists("appleapp", "clazz", Constant.APP_CACHE_SECONDS); - } - - @Override - protected long getExpireSeconds() { - return Constant.APP_CACHE_SECONDS; - } } diff --git a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java index 5d906a9..dcdc7bb 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java @@ -1,19 +1,7 @@ package com.miti99.storescraperbot.repository; -import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.GoogleApp; -import com.miti99.storescraperbot.util.MongoDBUtil; public class GoogleAppRepository extends AbstractCollectionRepository { public static final GoogleAppRepository INSTANCE = new GoogleAppRepository(); - - static { - // Create TTL index for cached data - MongoDBUtil.createTTLIndexIfNotExists("googleapp", "clazz", Constant.APP_CACHE_SECONDS); - } - - @Override - protected long getExpireSeconds() { - return Constant.APP_CACHE_SECONDS; - } } diff --git a/src/main/java/com/miti99/storescraperbot/util/MongoDBUtil.java b/src/main/java/com/miti99/storescraperbot/util/MongoDBUtil.java index 4fa0fb5..261acec 100644 --- a/src/main/java/com/miti99/storescraperbot/util/MongoDBUtil.java +++ b/src/main/java/com/miti99/storescraperbot/util/MongoDBUtil.java @@ -1,19 +1,20 @@ package com.miti99.storescraperbot.util; -import static com.miti99.storescraperbot.env.Environment.MONGODB_DATABASE_NAME; import static com.miti99.storescraperbot.env.Environment.MONGODB_CONNECTION_STRING; -import static com.miti99.storescraperbot.env.Environment.MONGODB_USERNAME; -import static com.miti99.storescraperbot.env.Environment.MONGODB_PASSWORD; +import com.miti99.storescraperbot.constant.Constant; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoException; +import com.mongodb.ServerApi; +import com.mongodb.ServerApiVersion; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; -import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; -import com.mongodb.client.model.Indexes; -import com.mongodb.client.model.CreateIndexOptions; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.log4j.Log4j2; +import org.bson.Document; @Log4j2 @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -22,26 +23,31 @@ public class MongoDBUtil { public static final MongoDatabase DATABASE; static { - String connectionString = MONGODB_CONNECTION_STRING; - String username = MONGODB_USERNAME; - String password = MONGODB_PASSWORD; - - String mongoUri; - if (username != null && !username.isEmpty() && password != null && !password.isEmpty()) { - mongoUri = String.format("mongodb://%s:%s@%s", username, password, connectionString); - } else { - mongoUri = connectionString; + var serverApi = ServerApi.builder().version(ServerApiVersion.V1).build(); + var connectionString = new ConnectionString(MONGODB_CONNECTION_STRING); + var settings = + MongoClientSettings.builder() + .applyConnectionString(connectionString) + .serverApi(serverApi) + .build(); + MONGO_CLIENT = MongoClients.create(settings); + var databaseName = + connectionString.getDatabase() != null + ? connectionString.getDatabase() + : Constant.DEFAULT_DATABASE_NAME; + DATABASE = MONGO_CLIENT.getDatabase(databaseName); + try { + DATABASE.runCommand(new Document("ping", 1)); + log.info("Pinged your deployment. You successfully connected to MongoDB!"); + } catch (MongoException e) { + log.error(e); } - - MONGO_CLIENT = MongoClients.create(mongoUri); - DATABASE = MONGO_CLIENT.getDatabase(MONGODB_DATABASE_NAME); - log.info("MongoDB connection established to database: {}", MONGODB_DATABASE_NAME); } public static void createCollectionIfNotExists(String collectionName) { try { boolean collectionExists = false; - for (String name : DATABASE.listCollectionNames()) { + for (var name : DATABASE.listCollectionNames()) { if (name.equals(collectionName)) { collectionExists = true; break; @@ -58,32 +64,4 @@ public class MongoDBUtil { log.error("createCollectionIfNotExists error - collectionName: '{}'", collectionName, e); } } - - public static void createTTLIndexIfNotExists(String collectionName, String fieldName, long expireAfterSeconds) { - try { - MongoCollection collection = DATABASE.getCollection(collectionName); - - // Check if TTL index already exists - boolean indexExists = false; - for (var index : collection.listIndexes()) { - String indexOptions = index.toJson(); - if (indexOptions.contains("\"expireAfterSeconds\": " + expireAfterSeconds)) { - indexExists = true; - break; - } - } - - if (!indexExists) { - CreateIndexOptions options = new CreateIndexOptions().expireAfter(expireAfterSeconds, java.util.concurrent.TimeUnit.SECONDS); - collection.createIndex(Indexes.descending(fieldName), options); - log.info("TTL index created on {} in collection {} with expire time: {} seconds", - fieldName, collectionName, expireAfterSeconds); - } else { - log.info("TTL index already existed on {} in collection {}", fieldName, collectionName); - } - } catch (Exception e) { - log.error("createTTLIndexIfNotExists error - collectionName: '{}', fieldName: '{}'", - collectionName, fieldName, e); - } - } -} \ No newline at end of file +}