问题
I've following Realm objects (init and other non-essential properties removed for brevity) in my Swift app
@objcMembers
class Person: Object {
dynamic var id: String = ""
dynamic var name: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
@objcMembers
class Project: Object {
dynamic var projectId: Int = 0
dynamic var manager: Person?
var tasks = List<Task>()
dynamic var lastTask: Task?
override static func primaryKey() -> String? {
return "projectId"
}
}
@objcMembers
class Task : Object {
dynamic var project = LinkingObjects(fromType: Project.self, property: "tasks")
dynamic var taskId: String = ""
dynamic var description: String = ""
dynamic var createDate: Date = Date()
override static func primaryKey() -> String? {
return "taskId"
}
}
So if there are 2 project members
Person(id: 1, name: "Foo")
Person(id: 2, name: "Bar")
and multiple projects,
Project(projectId: 100, manager: , messages: [a1, a2, a3], lastMessage: )
a1 = Task(project: <#100>, taskId: "a1", description: "Task 1 about project 100", createDate: Date() )
a2 = Task(project: <#100>, taskId: "a2", description: "Task 2 about project 100", createDate: Date() )
a3 = Task(project: <#100>, taskId: "a3", description: "Task 3 about project 100", createDate: Date() )
Project(projectId: 101, manager: , messages: [a1, a2, a3], lastMessage: )
b1 = Task(project: <#101>, taskId: "b1", description: "Task 1 about project 101", createDate: Date() )
b2 = Task(project: <#101>, taskId: "b2", description: "Task 2 about project 101", createDate: Date() )
b3 = Task(project: <#101>, taskId: "b3", description: "Task 3 about project 101", createDate: Date() )
b4 = Task(project: <#101>, taskId: "b3", description: "Task 3 about project 101", createDate: Date() )
Project(projectId: 102, manager: , messages: [a1, a2, a3], lastMessage: )
c1 = Task(project: <#102>, taskId: "c1", description: "Task 1 about project 102", createDate: Date() )
Project(projectId: 103, manager: , messages: [a1, a2, a3], lastMessage: )
d1 = Task(project: <#103>, taskId: "d1", description: "Task 1 about project 103", createDate: Date() )
d2 = Task(project: <#103>, taskId: "d2", description: "Task 2 about project 103", createDate: Date() )
d3 = Task(project: <#103>, taskId: "d3", description: "Task 3 about project 103", createDate: Date() )
In my ProjectsViewController
I can get my Realm results as
func getProjects() -> Results<Project> {
let results: Results<Conversation> = database
.objects(Conversation.self)
.sorted(byKeyPath: "lastTask.createDate", ascending: false)
return results
}
[Side note - If there is a better way of sorting the results based on last item of tasks List then do let me know. That'll make the use lastTask var redundant.]
which will display in my table view as
===================
Projects
-------------------
Foo
Project 100
Task a3
-------------------
Bar
Project 101
Task b4
-------------------
Foo
Project 102
Task c1
-------------------
Bar
Project 103
Task d3
-------------------
Question: How do I group the results in Realm query so I get a dictionary of grouped Array of results, such as
Foo -> [Project 100, Array of Tasks], [Project 102, Array of Tasks]
Bar -> [Project 101, Array of Tasks], [Project 103, Array of Tasks]
and they're tracked via NotificationToken for all inserts / updates. Also I want to dislay them grouped by sections in the table view.
===================
Projects (Grouped)
-------------------
Foo (Section Header)
-------------------
Project 100
Task a3
-------------------
Project 102
Task c1
-------------------
-------------------
Bar (Section Header)
-------------------
Project 101
Task b4
-------------------
Project 103
Task d3
-------------------
回答1:
I'll answer based on what I think you're asking.
If I understand correctly, you want to find a dictionary with the Person as the key, the values being a dictionary with Project ID (or Project) as the key and values of an array of tasks. i.e.
let result : [Person:[Project:[Task]]] = .....
If this isn't correct, you can probably take the ideas here and massage them into your ideal.
As you want to key by Person, I'd add a reverse lookup property to the Person class - and this is probably the main thing you're missing. Look at this section of the manual for guidance: (https://realm.io/docs/swift/latest/#inverse-relationships), and then add this property to Person:
let projects = LinkingObjects(fromType: Project.self, property: "manager")
I would then add a computed property to Person to retrieve the projects and tasks. This creates an array since that was asked for in the question.
var projectsAndTasks : [Project:[Task]]
{
var result : [Project:[Task]] = [:]
for project in projects
{
result[project] = project.tasks.map { $0 }
}
return result
}
If you want the tasks to be sorted, then add a computed property to Projects called sortedTasks that does that for you.
Once that's done, you can add a function somewhere (either global or static to Person) to add the results for all objects of Person into a single dictionary. E.g. :
extension Realm
{
var allPersonsAndProjects : [Person:[Project:[Task]]]
{
var result : [Person:[Project:[Task]]] = []
let persons = objects(Person.self)
for person in persons
{
result[person] = person.projectsAndTasks
}
return result
}
}
Forgive any compile errors.
来源:https://stackoverflow.com/questions/55182360/swift-group-realm-query-results