Мне нужна транзакция Vapor Fluent, переведенная на SQLKit. Можете помочь мне с этим?

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

Этот запрос возвращает дубликаты, потому что используется левое соединение по штрихкодам. И мне нужно использовать distinct, чтобы вернуть уникальные продукты. Как я могу переписать его с использованием SQLKit или Raw SQL, чтобы получить модели Fluent в ответ?

try await Product.query(on: db)
    .with(\.$info) {
      $0.with(\.$properties)
        .with(\.$consumer)
    }
    .with(\.$barcodes)
    .join(parent: \.$info)
    .join(children: \.$barcodes, method: .left)
    .join(children: \.$consumerProducts, method: .left)
    .join(from: ConsumerProduct.self, parent: \.$consumer, method: .left)
    .join(from: ProductInfo.self, children: \.$properties, method: .left)
    .group(.and) {
      if onlyProductList {
        $0.group(.and) {
          $0.filter(ConsumerProduct.self, \.$consumer.$id == consumerID)
            .filter(ConsumerProduct.self, \.$isHidden == isHidden)
        }
      } else {
        $0.group(.or) {
          $0.filter(ProductInfo.self, \.$consumer.$id == consumerID)
            .filter(ProductInfo.self, \.$consumer.$id == .null)
        }
      }
      $0.group(.or) {
        $0.group(.and) {
          for searchInput in searchInput.parts {
            $0.group(.or) {
              $0.filter(ProductInfo.self, \.$name, .custom("ilike"), "%\(searchInput)%")
                .filter(ProductInfo.self, \.$origin, .custom("ilike"), "%\(searchInput)%")
                .filter(Barcode.self, \.$value, .custom("ilike"), "%\(searchInput)%")
                .filter(InfoProperty.self, \.$title, .custom("ilike"), "%\(searchInput)%")
                .filter(InfoProperty.self, \.$value, .custom("ilike"), "%\(searchInput)%")
            }
          }
        }
      }
      .group(.or) {
        if let since {
          $0.filter(\.$updated >= since)
            .filter(ProductInfo.self, \.$updated >= since)
            .filter(Barcode.self, \.$updated >= since)
            .filter(InfoProperty.self, \.$updated >= since)
        }
      }
    }
    .sort(ProductInfo.self, \.$name)
    .sort(\.$volume)
    .paginate(for: request)

.

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

Преобразование запроса Vapor Fluent в SQLKit: Достижение уникальных продуктов с использованием DISTINCT

В современных веб-приложениях часто возникают ситуации, требующие извлечения данных с использованием различных ORM (Object-Relational Mapping) библиотек, таких как Vapor Fluent и SQLKit. При работе с большими объемами данных, особенно когда вам нужно избежать дублирования записей, вопрос оптимизации запросов приобретает особую актуальность.

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

Исходный Запрос на Fluent

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

try await Product.query(on: db)
    .with(\.$info) {
      $0.with(\.$properties)
        .with(\.$consumer)
    }
    .with(\.$barcodes)
    .join(parent: \.$info)
    .join(children: \.$barcodes, method: .left)
    .join(children: \.$consumerProducts, method: .left)
    .join(from: ConsumerProduct.self, parent: \.$consumer, method: .left)
    .join(from: ProductInfo.self, children: \.$properties, method: .left)
    // Далее идут фильтры и условия группировки
    .sort(ProductInfo.self, \.$name)
    .sort(\.$volume)
    .paginate(for: request)

Преобразование в SQLKit

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

let products = try await db.query(Product.self)
    .distinct()
    .with(\.$info) {
        $0.with(\.$properties)
         .with(\.$consumer)
    }
    .with(\.$barcodes)
    .join(parent: \.$info)
    .join(children: \.$barcodes, method: .left)
    .join(children: \.$consumerProducts, method: .left)
    .join(from: ConsumerProduct.self, parent: \.$consumer, method: .left)
    .join(from: ProductInfo.self, children: \.$properties, method: .left)
    .filter(ConsumerProduct.self, \.$consumer.$id == consumerID)
    // Добавьте дополнительные фильтры в зависимости от вашего запроса
    .sort(ProductInfo.self, \.$name)
    .sort(\.$volume)
    .paginate(for: request)

Важно понимать

  • Использование DISTINCT: Благодаря добавлению метода .distinct(), мы обеспечиваем возврат уникальных записей, что предотвращает отображение дублирующихся продуктов.
  • Фильтры и условия: Обратите внимание на структуру условий фильтров. Вы можете повторно применять логику из вашего исходного запроса, контролируя тем самым, какие данные должны быть возвращены.
  • Оптимизация производительности: SQLKit позволяет более эффективно управлять запросами, что может способствовать повышению производительности вашего приложения.

Заключение

Преобразование запросов из Fluent в SQLKit может показаться сложной задачей, однако, используя возможности SQLKit, можно значительно сократить время выполнения запросов и избежать проблем с дублированием данных. Использование оператора DISTINCT в SQLKit позволит гарантировать, что результаты будут содержать только уникальные продукты, что критически важно для эффективного управления данными в приложениях, ориентированных на пользователя.

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

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

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