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

Я просто хочу поделиться тем, что у меня есть приложение Core Data со следующими функциями:

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

Каждый из них представляет собой кнопку, которую пользователь может нажать, чтобы отфильтровать данные, например (слева направо): «Все», «Входящие», «Архив», «Еще», «Хорошо», «Зло», «Важно». Вы также заметите, что каждая кнопка имеет счетчик.

В моей ViewModel у меня есть функция для подсчета каждого из них, которая вызывается, когда в приложении onAppear()

func countItem() -> (countTotal: Int, countArchive: Int, countGood: Int, countEvil: Int, countImportant: Int) {
    let request: NSFetchRequest<ThoughtEntity> = ThoughtEntity.fetchRequest()
    
    request.predicate = NSPredicate(format: "thoughts != %@", "")
    let items1 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countTotalPredicate = items1.count
    
    request.predicate = NSPredicate(format: "isArchive == true")
    let items2 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countArchivePredicate = items2.count
    
    request.predicate = NSPredicate(format: "type CONTAINS %@", "good")
    let items3 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countGoodPredicate = items3.count
    
    request.predicate = NSPredicate(format: "type CONTAINS %@", "evil")
    let items4 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countEvilPredicate = items4.count
    
    request.predicate = NSPredicate(format: "type CONTAINS %@", "important")
    let items5 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countImportantPredicate = items5.count

    return (countTotalPredicate, countArchivePredicate, countGoodPredicate, countEvilPredicate, countImportantPredicate)
}

Код работает достаточно хорошо.

Мне интересно, есть ли лучший способ сделать это вместо того, чтобы получать данные из базы данных 5 раз? Возможно, «стоимость» извлечения невелика, так что это не имеет значения, но мне интересно, есть ли лучший и более эффективный способ сделать это?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать метод count(for:) в viewContext, чтобы вернуть только количество, а не все объекты.

let request: NSFetchRequest<ThoughtEntity> = ThoughtEntity.fetchRequest()
        
request.predicate = NSPredicate(format: "thoughts != %@", "")
let countTotalPredicate = try? manager.container.viewContext.count(for: request)) ?? 0

Спасибо. Это хороший совет. Но мне все равно нужно сделать это 5 раз, верно?

ringgit malaysia 17.04.2024 09:04

Что ж, вам действительно нужно пять разных счетчиков с пятью разными предикатами, если я не правильно понимаю ваши требования. Использование метода подсчета заставляет Core Data выполнять меньше тяжелой работы и требует на пять строк кода меньше.

Magnas 17.04.2024 09:30

Да, вы правильно понимаете мое требование. Спасибо.

ringgit malaysia 17.04.2024 12:25

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

Hal Mueller 17.04.2024 22:31

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

Что-то вроде этого

let request = NSFetchRequest<NSDictionary>(entityName: "ThoughtEntity")
request.sortDescriptors = [NSSortDescriptor(keyPath: \ThoughtEntity.type, ascending: false)]
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [
    NSPredicate(format: "type CONTAINS %@", "good"), 
    NSPredicate(format: "type CONTAINS %@", "evil"),
    NSPredicate(format: "type CONTAINS %@", "important")
]

request.predicate = predicate

let keyPath = NSExpression(forKeyPath: "type")
let expression = NSExpression(forFunction: "count:", arguments: [keyPath])
let countDescription = NSExpressionDescription()
countDescription.expression = expression
countDescription.name = "count"
countDescription.expressionResultType = .integer64AttributeType

request.propertiesToGroupBy = ["type"]
request.propertiesToFetch = ["type", countDescription]
request.resultType = .dictionaryResultType

Однако обратите внимание: если объект не содержит большого количества объектов, возможно, будет быстрее получить все за один запрос, а затем выполнить подсчет в памяти, поскольку даже с этим решением вам потребуется выполнить 3 запроса.

Возможно, предикат можно улучшить, чтобы использовать что-то вроде sql IN (...)

Joakim Danielson 17.04.2024 10:03

Я ценю ваш ответ, Йоаким. Хотя я собираюсь следовать ответу Магнаса, потому что я понимаю код, я также изучу ваш ответ для своего обучения. Спасибо.

ringgit malaysia 18.04.2024 04:09

Нет проблем, другой ответ более простой, но я все же хотел показать эту альтернативу.

Joakim Danielson 18.04.2024 08:29

Другие вопросы по теме