2

I am currently trying out Realm on a test project and I have been struggling with removing a specific object from a List. LensDBObject and ListDBObject. LensDBObject contains a list of lenses and ListDBObject are lists of existing lenses. A lens can be in multiple lists and I'd like to remove a specific lens from a specific list but not remove if from the other lists.

Below are my two classes:

@objcMembers class LensDBObject: Object {

   dynamic var id = UUID().uuidString
   dynamic var manufacturer = ""
   dynamic var series = ""
   dynamic var serial = ""
   dynamic var isSelected = false

   override static func primaryKey() -> String? {
       return "id"
   }

   let objects = LinkingObjects(fromType: ListDBObject.self, property: "lensList")

}

@objcMembers class ListDBObject: Object {
   dynamic var listName = ""
   let lensList = List<LensDBObject>()

}

Below is my code to find a specific lens in the list I want. The values returned are what I expect.

let listToSearch = realm.objects(ListDBObject.self).filter("listName == %@", "List 542")
print(listToSearch)
let filteredResults = listToSearch[0].lensList.filter("manufacturer == %@ AND series == %@ AND serial == %@", "Panavision" , "Primo Prime", "407")
print(filteredResults)

However, when I try to delete filteredResults, it deletes it from the lensDBOject altogether. I just want to be able to delete this specific lens from this specific list.

try! realm.write {
    realm.delete(filteredResults)
}

I tried using for loops to get the index of the lens in the list and then delete it directly from that. But it still deletes the lens everywhere.

Am I missing something? Should I be using a one-to-many relationship as opposed to a LinkingObject?

Thanks for you help!

downuts
  • 35
  • 1
  • 3

1 Answers1

1

Try something like this. You only want to remove the lens from the list, not delete it from the Realm.

try! realm.write {
    filteredResults.forEach { lens in
        if let index = listToSearch[0].lensList.index(of: lens) {
            listToSearch[0].lensList.remove(at: index)
        }
    }
}

Note that this will remove from that one specific list all lenses that match your filter.

Edit: Updated to reflect Realm's custom List class.

The if let is required, because index(of:) could potentially return nil if the object is not found in the list. Additionally, we must do it one item at a time rather than getting all the indexes first, since removing an item would cause the index array to be wrong.

Samah
  • 1,224
  • 2
  • 13
  • 15
  • Thanks for your help! Now I understand why on the RealmBrowser, when I right click on a lens in a list I get the options: Remove object from array or Remove object from array and delete. It needs to be removed, not deleted. It works :) – downuts Jan 31 '18 at 22:29
  • I'm glad that worked, I just typed it in a text editor without testing! – Samah Jan 31 '18 at 22:33
  • filteredResults.forEach({ _ in listToSearch[0].lensList.remove(at: 0) }) is the correct code fwiw :) – downuts Jan 31 '18 at 22:58
  • No, that's different. `remove(at: 0)` will remove the first element. `$0` will use the argument passed to `forEach` (the one you have marked as underscore). See: https://stackoverflow.com/questions/36144322/what-does-0-and-1-mean-in-swift-closures – Samah Jan 31 '18 at 23:08
  • Sorry for the delay. If I try `filteredResults.forEach{listToSearch[0].lensList.remove(at: $0)}` then $0 refers to a lensDBObject and not and index (Int). I'm deleting from a tableView, so the filteredResult should only return 1 result at a time but I'd be interested do it the right way regardless. – downuts Feb 01 '18 at 22:21
  • Apologies, I forgot Realm has its own `List` class that doesn't support removing by object references. I'll update the answer. – Samah Feb 01 '18 at 23:12
  • God this database is an absolute buzzword .... Its mindboggling list.remove(object) isn't a thing that exists in a production quality db in 2019. Wheee observable shits the bed again... – Shayne Jun 11 '19 at 07:44