Currently, I am using this code to delete all future repeat transactions:
let futureRecurringTransactions = self.transactions.filter(NSPredicate(format: "transactionDescription == %@ && transactionDate >= %@ && transactionCategory == %@", transaction!.transactionDescription!, transaction!.transactionDate as CVarArg, transaction!.transactionCategory!))
for transaction in futureRecurringTransactions {
try! self.realm.write {
self.realm.delete(transaction)
}
}
Here is my Realm data model:
import RealmSwift
class Transaction: Object {
@objc dynamic var transactionDescription: String? = nil
@objc dynamic var transactionAmount = 0.0
@objc dynamic var transactionDate = Date()
@objc dynamic var transactionCategory: Category? = nil
@objc dynamic var repeatInterval = ""
@objc dynamic var isCleared = false
@objc dynamic var transactionName = ""
@objc dynamic var transactionID = UUID().uuidString
convenience init(theDate: Date) {
self.init()
self.transactionDate = theDate
}
override static func primaryKey() -> String? {
return "transactionID"
}
}
The code works, but it feels like the way I'm doing it is amateur and clunky. Is there a better way that is more accurate and proper?
I thought it might be good to utilize the transactionID , but each transaction has a unique transactionID, so I'm not sure how that would work.
What I typically do is create a unique NSPredicate for each constraint you want to place on the collection. You can mix and match each predicate to form a unique set of filters. For example:
extension NSPredicate {
static func transactionDescriptionEqualTo(_ description: String?) -> NSPredicate {
if let description = description {
return .init(format: "transactionDescription == %@", description)
}
return .init(format: "transactionDescription == nil")
}
static func transactionCategoryEqualTo(_ category: Category?) -> NSPredicate {
if let category = category {
return .init(format: "transactionCategory == %@", category)
}
return .init(format: "transactionCategory == nil")
}
static func transactionDateIsAfter(_ date: Date) -> NSPredicate {
return .init(format: "transactionDate >= %@", date as NSDate)
}
static func transactionIDNotEqualTo(_ id: String) -> NSPredicate {
return .init(format: "transactionID != %@", id)
}
static func futureRepeats(of transaction: Transaction) -> NSPredicate {
return NSCompoundPredicate(andPredicateWithSubpredicates: [
.transactionDescriptionEqualTo(transaction.transactionDescription),
.transactionCategoryEqualTo(transaction.transactionCategory),
.transactionDateIsAfter(transaction.transactionDate),
.transactionIDNotEqualTo(transaction.transactionID),
])
}
}
Also note that you don't need to loop over the results. You can delete all objects in the results like this:
let realm = try Realm()
try realm.write {
realm.delete(transactions.filter(.futureRepeats(of: transaction)))
}
Lastly, it's a good idea to include the transactionID as a constraint. Otherwise the original transaction will be included in the results.