Realm에 Object를 저장할 때 Dictionary혹은 Json 구조처럼 저장하고 싶을 때가 있다.
A반 -------- 이름 : 스위프트
| |____ 나이 : 10
|
|_______ 이름 :파이썬
|____ 나이: 70
대충 이런 구조..?
{
"title":"이석원님 작품",
"bookList":[
{
"title":"2인조",
"image": "2인조",
"author" : "이석원",
"date" : "2021-03-10"
},
{
"title": "우리가 보낸 가장 긴 밤",
"image": "우리가 보낸 가장 긴 밤",
"author" : "이석원",
"date" : "2021-03-10"
}
]
}
json으로 보면 이런 구조!
1 : N의 구조를 Realm에서 모델로 구성하려면 어떻게 해야할까?
Realm에서는 현재 dictionary구조를 지원하고 있지 않기 때문에 nested-object 형태로 구성해야한다.
(+ beta버전으로 현재 Map을 지원하고 있다! https://docs.mongodb.com/realm/sdk/ios/data-types/map/)
아무튼 nested-object의 형태를 보자.
import Foundation
import RealmSwift
class TodoData: Object {
@objc dynamic var date: String = ""
@objc dynamic var isToday: Bool = true
let todos: List<Todo> = List<Todo>()
override public static func primaryKey() -> String? {
return "date"
}
convenience init(date: String) {
self.init()
self.date = date
self.isToday = isToday
}
}
class Todo: Object {
@objc dynamic var dateInt: Int = 0
@objc dynamic var title: String = ""
@objc dynamic var content: String = ""
@objc dynamic var isDone: Bool = false
let ofTodo = LinkingObjects(fromType: TodoData.self, property: "todos")
convenience init(dateInt: Int,title: String, content: String, isDone: Bool) {
self.init()
self.dateInt = dateInt
self.title = title
self.content = content
self.isDone = isDone
}
}
TodoData에 ToDo들이 여러 개 들어올 수 있는 상황인 것이다.
이 때 List<Object> 타입으로 배열을 선언할 수 있다!
자 여기서 원래 realm에 데이터를 add하는 방법대로 진행해보면 그냥 업데이트만 된다..!
try! self.realm.write {
// TodoData 객체를 만들어준다.
let main = TodoData(date: now)
// TodoData 하위에 들어갈 Todo를 만들어준다.
let sub = Todo(dateInt: todayInt, title: title, content: content, isDone: isDone)
// 객체 연결하기
main.todos.append(sub)
// realm에 추가
self.realm.add(main, update: Realm.UpdatePolicy.all)
}
}
이렇게 데이터를 추가하게 되면!
하나의 TodoData에 하나의 Todo만 매칭이 되는 1:1 관계가 되어버린다.
[TodoData]
date : 2021년 07월 01일
Todo - dateInt : 20210701
- title : "clean up"
- content : "room/garden"
- isDone : false
여기서 아무리 새로운 데이터를 넣어봤자 기존의 Todo 부분만 다른 값으로 변경되며, 개수는 그대로 1개로 유지가 된다.
이 때 1:N으로 만들고 싶다면, 기존의 데이터들도 append해주고 새로운 값을 append해주면 된다.
즉 기존의 값을 불러와서 먼저 붙여주고, 그 다음 새로운 값을 붙여주게 되는 것이다.
try! self.realm.write {
// TodoData 객체를 만들어준다.
let main = TodoData(date: now)
// TodoData 하위에 들어갈 Todo를 만들어준다.
let sub = Todo(dateInt: todayInt, title: title, content: content, isDone: isDone)
// 기존 값들을 불러와서 붙임
let old = self.realm.objects(Todo.self).filter("dateInt = \(self.today().first!)")
for i in 0..<old.count {
main.todos.append(old[i])
}
// 새로운 값 붙이기
main.todos.append(sub)
// 추가
self.realm.add(main, update: Realm.UpdatePolicy.all)
}
}
다만 데이터가 얼마 없을 때만 이 방법을 채택해서 사용해야 할 것 같다.
데이터가 방대한 상황에 매번 기존의 값을 읽고, 추가하는 건 비효율적인 것 같다.
우선은 하루의 데이터가 얼마 되지 않는 상황이기에 해당 방법으로 해결하였다!
잘 들어갔다면 List<Todo>에 숫자가 계속 늘어나는 것을 볼 수 있을 것이다!
+++ 이렇게 추가해도 가능하다!
try! self.realm.write {
let sub = Todo(title: title, content: content, isDone: isDone)
if let old = self.realm.objects(TodoData.self).filter("dateInt == \(todayInt)").first {
old.todos.append(sub)
} else {
let main = TodoData(date: now, dateInt: todayInt)
main.todos.append(sub)
self.realm.add(main, update: Realm.UpdatePolicy.all)
}
}
끄읕