Вопрос или проблема
Этот запрос возвращает дубликаты, потому что используется левое соединение по штрихкодам. И мне нужно использовать 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 позволит гарантировать, что результаты будут содержать только уникальные продукты, что критически важно для эффективного управления данными в приложениях, ориентированных на пользователя.
Таким образом, правильное написание и оптимизация запросов не только улучшает производительность приложения, но и способствует повышению его надежности и удобства.