[RealmSwift] Nested-Object value add 팁 (중복 방지, 업데이트 방지)
👨🏻‍💻iOS 공부/iOS & Swift

[RealmSwift] Nested-Object value add 팁 (중복 방지, 업데이트 방지)

728x90
반응형

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/)

 

Map (beta) - iOS SDK — MongoDB Realm

Realm SDKs > MongoDB Realm iOS SDK > Realm Data Types - iOS SDK New in version 10.8.0: MapThis feature is currently in beta. We encourage you to try out the feature and give feedback, but please be aware that:The API may change.New data types are not backw

docs.mongodb.com

 

아무튼 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)
    } 
}

 

끄읕

728x90
반응형