【问题标题】:Filtering Realm with nested subqueries使用嵌套子查询过滤领域
【发布时间】:2020-04-12 07:28:11
【问题描述】:

我的应用有这样的数据。

class ShelfCollection: Object {
  let shelves: List<Shelf>
}

class Shelf: Object {
  let items: List<Item>
}

class Item: Object {
  var name: String
  let infos: List<String>
}

我正在尝试获取架子集合中的所有架子,其中任何项目都通过名称或信息列表中的元素与查询匹配。据我了解,这个谓词应该是正确的,但它崩溃了。

let wildQuery = "*" + query + "*"
shelfResults = shelfCollection.shelves.filter(
    "SUBQUERY(items, $item, $item.name LIKE[c] %@ OR SUBQUERY($item.infos, $info, info LIKE[c] %@).@count > 0).@count > 0",
    wildQuery, wildQuery
)

它符合 NSPredicate,但是当 Realm 尝试解析它时崩溃,抛出我

'RLMException', reason: 'Object type '(null)' not managed by the Realm'

我怀疑嵌套子查询可能是失败的原因,但我对NSPredicate 的了解还不够,无法确定。这是一个可接受的查询吗?我怎样才能使它..工作?

【问题讨论】:

    标签: ios swift realm nspredicate


    【解决方案1】:

    这是一个答案和一个解决方案,但对象的结构方式会存在许多问题,这些问题可能会导致其他问题。由于许多对象出现在其他对象中,因此很难创建匹配的数据集。

    问题:

    Realm 目前无法过滤基元列表

    编辑: 10.7 版增加了对过滤器/查询以及基元聚合函数的支持,因此以下信息不再完全有效。但是,这仍然需要注意。

    所以这个 Item 属性不能用于过滤:

    let infos: List<String>
    

    但是,您可以创建另一个具有 String 属性的对象并对该 对象

    进行过滤
    class InfoClass: Object {
        @objc dynamic var info_name = ""
    }
    

    然后 Item 类看起来像这样

    class Item: Object {
      var name: String
      let infos = List<InfoClass>()
    }
    

    然后您根据 InfoClass object 进行过滤,而不是它的字符串属性。所以你会有一些对象

    let info0 = InfoClass()
    info0.info_name = "Info 0 name"
        
    let info1 = InfoClass()
    info1.info_name = "Info 1 name"
    
    let info2 = InfoClass()
    info2.info_name = "Info 2 name"
    

    它们存储在 Item->infos 列表中。那么问题

    我正在尝试获取架子集合中的所有架子...

    表示您要过滤的集合,在本例中为 c0,其项目在其列表中包含特定信息的货架。假设我们想要获取列表中包含 info2 的货架

     //first get the info2 object that we want to filter for
     guard let info2 = realm.objects(InfoClass.self).filter("info_name == 'Info 2 name'").first else {
        print("info2 not found")
        return
    }
    
    print("info2 found, continuing")
    
    //get the c0 collection that we want to get the shelves for
    if let c0 = realm.objects(ShelfCollection.self).filter("collection_name == 'c0'").first {
        let shelfResults = c0.shelves.filter("ANY items.infoList == %@", info2)
        for shelf in shelfResults {
            print(shelf.shelf_name)
        }
    } else {
        print("c0 not found")
    }
    

    我省略了对 name 属性的过滤,因为您已经知道该怎么做。

    这里的问题是信息可能出现在许多项目中,而这些项目可能出现在许多货架列表中。因此,由于数据的深度,对于我的测试数据,很难让过滤器返回谨慎的数据 - 如果我有示例数据可以使用,它可能会更有意义(对我而言)。

    无论哪种方式,答案都适用于这个用例,但我认为另一种结构可能更好,但我不知道完整的用例,所以很难提出建议。

    【讨论】:

    • 谢谢杰!没有看到原语在任何地方都是不可过滤的......另外,我的查询中有一个错字,info 而不是内部子查询中的$info
    猜你喜欢
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多