这是我的Realm对象的外观:
class Restaurant: Object {
@objc dynamic var name: String? = nil
let meals = List<Meal>()
}
class Meal: Object {
@objc dynamic var mealName: String? = nil
let tag = RealmOptional<Int>()
}
我正在尝试获取带有某些标签的所有餐点(我知道我可以为特定标签过滤所有Meal
类型的Realm对象),但是目标是获取所有Restaurant
对象,并根据标签值过滤Meal
个子对象。
我尝试过这样的过滤:
restaurants = realm.objects(Restaurant.self).filter("meals.@tags IN %@", selectedTags)
但是这行不通。有没有一种方法可以根据子对象列表中的值来过滤结果?
为澄清这个问题,这是一个示例,说明如何进行过滤
为selectedTags = [1, 2, 3]
这是保存在Realm中的整个Restaurant
模型。
[Restaurant {
name = "Foo"
meals = [
Meal {
mealName = "Meal 1"
tag = 1
},
Meal {
mealName = "Meal 2"
tag = 2
},
Meal {
mealName = "Meal 7"
tag = 7
}
]
}]
过滤应返回以下内容:
[Restaurant {
name = "Foo"
meals = [
Meal {
mealName = "Meal 1"
tag = 1
},
Meal {
mealName = "Meal 2"
tag = 2
}
]
}]
答案 0 :(得分:0)
简而言之,您无法做自己要问的事情。至少不在Realm查询之内(因此,如果重要的话,可以从更新通知中受益)。毫无疑问,您可以通过非Realm过滤来构建某种包含所需内容的结构。
为了获得更好的答案,我们首先考虑一下您要作为查询结果生成的内容。正如您所说,您的上述尝试将无效。但是,您正在尝试通过让一些Restaurant
与某些条件匹配来过滤Meal
。这可能是可以实现的,但是您对Restaurant
类型的查询将产生Restaurant
的列表。每家餐厅仍将拥有其所有Meal
的自然属性,并且需要再次对餐点应用相同的过滤器。
在Restaurant
类中添加一个函数(如果您需要动态的搜索条件,如果过滤器始终是相同的标签,则使用计算属性)是有意义的,该类生成其{符合您条件的{1}}。
例如
Meal
所以我认为有两种选择。
extension Restaurant
{
var importantMeals : Results<Meal>
{
return meals.filter(...)
}
}
对象,如果其Restaurant
属性不为空,则将其添加到您自己的数据结构(集合或数组)中。然后在需要时使用相同的属性生成餐单。或者,您可以使用非Realm过滤器为您生成该查询。例如。 importantMeals
realm.objects(Restaurant.self).compactMap {$0}.filter { !$0.importantMeals.isEmpty }
)过滤所有Meal
。然后,您可以在realm.objects(Meal.self).filter(...)
类中添加LinkingObjects
属性,以使Meal
的集合具有相关的Restaurant
。正确的方法将取决于您要如何使用结果,但是我建议方法1可以使您正确。请注意,您可能希望在使用顺序对您来说是否很重要(例如,在Meal
中显示)之前对查询产生的结果进行排序,因为不能保证每个查询的对象顺序都相同执行。
答案 1 :(得分:0)
这是一种可能的解决方案-为餐厅中的每个用餐对象添加反向引用
class Restaurant: Object {
@objc dynamic var name: String? = nil
let meals = List<Meal>()
}
class Meal: Object {
@objc dynamic var mealName: String? = nil
let tag = RealmOptional<Int>()
@objc dynamic var restaurant: Restaurant? //Add this
}
然后使用您想要的标签查询该餐厅的餐点。
let results = realm.objects(Meal.self).filter("restaurant.name == %@ AND tag IN %@", "Foo", [1,2])
也可以利用LinkingObjects,但它取决于需要哪种查询以及饭店和餐饮之间的关系-在这种情况下,我假设为1-Many。
如果您想要所有餐厅,那么LinkingObjects是必经之路。
编辑:
另一个解决方案的想法。这将在不添加参考或逆关系的情况下起作用,并且将返回一系列带有选定标签的用餐餐厅。
let selectedTags = [1,2]
let results = realm.objects(Restaurant.self).filter( {
for meal in $0.meals {
if let thisTag = meal.tag.value { //optional so safely unwrap it
if selectedTags.contains(thisTag) {
return true //the tag for this meal was in the list, return true
}
} else {
return false //tag was nil so return false
}
}
return false
})