Лучшие практики для отслеживания прочитанных статей в Firestore, оставаясь в пределах лимитов бесплатного тарифа – SwiftUI/iOS [закрыто]

Вопрос или проблема

Я разрабатываю приложение для чтения новостей на iOS, которое считывает статьи из Firestore – пока что только для себя. Приложение должно отслеживать, какие статьи я прочитал, но меня беспокоит превышение дневной бесплатной квоты в 20 000 операций записи. В настоящее время я записываю несколько тысяч статей в день в базу данных. (Я не читаю их все, в основном просматриваю заголовки). Позже, возможно, если будет больше пользователей, экономия на операциях записи станет еще большей проблемой.

  1. Каков самый эффективный способ отслеживания статуса прочтения без чрезмерных операций записи?
  2. Нужно ли мне создавать отдельную коллекцию для статуса прочтения?
  3. Существуют ли лучшие подходы к решению этой задачи, оставаясь в пределах бесплатных квот?

Текущая настройка

struct Article {
    let id: String
    let title: String
    let content: String
    let isRead: Bool
    let timestamp: Date
}

Технические детали

  • Платформа: iOS/SwiftUI
  • База данных: Firebase Firestore
  • Ежедневные операции записи: ~1000-3000
  • Ограничения бесплатного тарифа вызывают беспокойство

Что я попробовал
Я рассматривал возможность обновления документа статьи напрямую:

func markAsRead(articleId: String) async throws {
    let ref = db.collection("articles").document(articleId)
    try await ref.updateData([
        "isRead": true,
        "readTimestamp": Date()
    ])
}
  • Приложение должно отслеживать статус прочтения/непрочтения для каждого пользователя
  • Поддержка оффлайн-режима была бы полезной, но не обязательной
  • Оперативные обновления не являются необходимыми

Обновление: Я рассматриваю другой подход, который может быть более эффективным:

Вместо того чтобы отмечать отдельные статьи как прочитанные, я мог бы сохранить только одну метку времени, представляющую, когда пользователь в последний раз ознакомился с их статьями:

// Структура в Firestore
users/{userId}/reading/{deviceId} {
    lastReadTimestamp: timestamp
}

// Обновить метку времени, когда пользователь читает статьи
func updateLastRead(userId: String, deviceId: String) async throws {
    let ref = db.collection("users").document(userId)
        .collection("reading").document(deviceId)

    try await ref.setData([
        "lastReadTimestamp": FieldValue.serverTimestamp()
    ])
}

// Запросить непрочитанные статьи
func getUnreadArticles(userId: String, deviceId: String) async throws -> [Article] {
    let readingDoc = try await db.collection("users")
        .document(userId)
        .collection("reading")
        .document(deviceId)
        .getDocument()

    let lastRead = readingDoc.data()?["lastReadTimestamp"] as? Timestamp ?? Timestamp(date: Date(timeIntervalSince1970: 0))

    let snapshot = try await db.collection("articles")
        .whereField("timestamp", isGreaterThan: lastRead)
        .getDocuments()

    return snapshot.documents.map { /* логика отображения */ }
}

Преимущества этого подхода:
Только одна операция записи за сеанс чтения вместо отметки каждой статьи
Эффективный запрос с использованием сравнения меток времени
Можно отслеживать статус прочтения на каждом устройстве
Хорошо масштабируется с большим количеством статей
Хорошо укладывается в лимиты бесплатной квоты
Будет ли это лучшим решением? Есть ли недостатки, которые я должен учесть?

Ответ или решение

Конечно! Давайте рассмотрим, как эффективно отслеживать прочитанные статьи в Firestore, придерживаясь пределов бесплатного тарифа, с точки зрения разработки iOS-приложения с использованием SwiftUI.

Полезные практики для отслеживания прочитанных статей в Firestore

1. Эффективное отслеживание прочитанных статей

Ваш текущий подход к записи статуса прочтения статьи может привести к избыточным записям в базе данных, что нецелесообразно, особенно если вы планируете, что охват пользователей будет увеличиваться. Вместо того чтобы обновлять каждую статью по мере её прочтения, разумнее использовать стратегию, которая требует минимального количества операций записи.

2. Хранение статуса в отдельной коллекции

Создание отдельной коллекции для статуса чтения может оказаться излишним и усложнить структуру вашей базы данных. Вместо этого будет более оптимально организовать данные на уровне пользователя и устройства.

Новая структура данных:
users/{userId}/reading/{deviceId} {
    lastReadTimestamp: timestamp
}

3. Использование одного таймстампа

Ваше обновление, основанное на хранении одного таймстампа lastReadTimestamp, представляет собой перспективный подход. Преимущества такого решения следующие:

  • Снижение операций записи: Вам нужно будет записывать только одну операцию на устройство за сессию чтения, что значительно уменьшит риск превышения лимитов.
  • Простота в обновлении данных: Запись таймстампа более интуитивно понятна, чем обновление отдельных статусов статей.
  • Гибкость в запросах: Вы сможете легко извлекать все статьи, которые были добавлены после последнего обновления времени чтения.

4. Запросы на получение непрочитанных статей

Ваш метод для получения непрочитанных статей основан на сравнении timestamp, что является эффективным и быстрым способом. JSON-запрос к Firestore выглядит оптимально:

func getUnreadArticles(userId: String, deviceId: String) async throws -> [Article] {
    let readingDoc = try await db.collection("users")
        .document(userId)
        .collection("reading")
        .document(deviceId)
        .getDocument()

    let lastRead = readingDoc.data()?["lastReadTimestamp"] as? Timestamp ?? Timestamp(date: Date(timeIntervalSince1970: 0))

    let snapshot = try await db.collection("articles")
        .whereField("timestamp", isGreaterThan: lastRead)
        .getDocuments()

    return snapshot.documents.map { /* логика маппинга */ }
}

5. Условия и недостатки

Несмотря на очевидные преимущества, следует рассмотреть некоторые недостатки:

  • Потеря индивидуального статуса прочтения: Ваша текущая реализация не позволяет отслеживать статус прочтения для каждой статьи в отдельности. Это может стать проблемой, если в будущем вы захотите добавить какую-то функциональность, основанную на этом статусе.
  • Ограничение на количество устройств: Ваш метод предполагает, что одно устройство будет обеспечивать только одно значение lastReadTimestamp. Если пользователь читает статьи на нескольких устройствах, может потребоваться возможность хранения отдельных таймстампов для каждого устройства.

Заключение

Оптимизация отслеживания прочитанных статей в Firestore через хранение единого таймстампа — это разумное решение, которое поможет вам оставаться в пределах бесплатных лимитов и упрощать управление данными. Несмотря на некоторые недостатки, предложенный вами способ является функциональным и эффективным для вашего текущего проекта. В будущем вы всегда сможете адаптировать его по мере роста количества пользователей и изменяющихся требований.

Оцените материал
Добавить комментарий

Капча загружается...