How to add relationships between objects?

Hello,

I have two base classes

struct ParseCategory: ParseObject {
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?
    var originalData: Data?
    
    var name: String?
    var index: Int?
    var icon: ParseFile?
    
    var articles: ParseRelation<Self>?
    
    func merge(with object: Self) throws -> Self {
        var updated = try mergeParse(with: object)
        if updated.shouldRestoreKey(\.name, original: object) {
            updated.name = object.name
        }
        if updated.shouldRestoreKey(\.index, original: object) {
            updated.index = object.index
        }
        if updated.shouldRestoreKey(\.icon, original: object) {
            updated.icon = object.icon
        }
        return updated
    }
}
struct ParseArticle: ParseObject {
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?
    var originalData: Data?

    // Custom properties
    var headline: String?
    var author: String?
    var lead: String?
    var body: String?
    var tail: String?
    
    var heroImage: ParseFile?
    var bodyImage: ParseFile?

    var sourceImage: ParseFile?
    var sourceUrl: String?
    
    var category: String?
    var breakingNews: Bool?
    var newsOfTheDay: Bool?

    // Implement your own version of merge
    func merge(with object: Self) throws -> Self {
        var updated = try mergeParse(with: object)
        if updated.shouldRestoreKey(\.headline, original: object) {
            updated.headline = object.headline
        }
        if updated.shouldRestoreKey(\.author, original: object) {
            updated.author = object.author
        }
        if updated.shouldRestoreKey(\.lead, original: object) {
            updated.lead = object.lead
        }
        if updated.shouldRestoreKey(\.body, original: object) {
            updated.body = object.body
        }
        if updated.shouldRestoreKey(\.tail, original: object) {
            updated.tail = object.tail
        }
        if updated.shouldRestoreKey(\.sourceUrl, original: object) {
            updated.sourceUrl = object.sourceUrl
        }
        if updated.shouldRestoreKey(\.category, original: object) {
            updated.category = object.category
        }
        if updated.shouldRestoreKey(\.breakingNews, original: object) {
            updated.breakingNews = object.breakingNews
        }
        if updated.shouldRestoreKey(\.newsOfTheDay, original: object) {
            updated.newsOfTheDay = object.newsOfTheDay
        }
        return updated
    }
}

I have newsgroups on my server. Logically, each group should contain a set of news related to this group.

When creating a news, I get the desired group by ID, create news and try to set a one-to-many relationship in the group.

First method:

func save(for article: Article, with categoryId: String) {
        if let parseCategory = try? ParseCategory.query("objectId" == categoryId).first() {
            let parseArticle = ParseArticle(article: article)
            if let savedArticle = try? parseArticle.save() {
                if let relationOperation = try? parseCategory.operation.addRelation("articles", objects: [savedArticle]) {
                    _ = try? relationOperation.save()
                }
            }
        }
}

Other method:

func save(for article: Article, with categoryId: String) {
        if let parseCategory = try? ParseCategory.query("objectId" == categoryId).first() {
            let parseArticle = ParseArticle(article: article)
            if let savedArticle = try? parseArticle.save() {
                do {
                    guard let newRelations = try parseCategory.relation?.add("articles", objects: [savedArticle]) else {
                        print("Error: should have unwrapped relation")
                        return
                    }
                    newRelations.save { result in
                        switch result {
                        case .success(let saved):
                            print("The relation saved successfully: \(saved)")
                        case .failure(let error):
                            print("Error saving role: \(error)")
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        }
}

None of the methods wants to save the relationship. I studied the documentation and tried different ways, but the relations on the server are empty and do not refer to the added instances.

What am I doing wrong?

What does your Xcode console log say? Is it printing your success statement or error messages? If it’s an error, what’s the error?

It says: The relation saved successfully

Maybe I added the relation incorrectly? That’s why I gave examples of my code. Can the category itself be updated? I tried to call the save method on the category, but the result did not change

If it says it saved, you should run the query code in the Playgrounds… I also don’t recommend calling the synchronous methods as you are doing, you should be using async/await or completion.

You are probably running into an issue with Parse Dashboard. Hit your browsers “refresh” button. Just clicking on the links won’t refresh the dashboard. I mention this problem with _Role, but haven’t had a chance to open an issue on Dashboard:

When in doubt, the Playground code is runnable, you should fork the repo, change the settings to point to your server and run the Playgrounds directly:

I printed my console:

The relation saved successfully: ParseCategory ({"objectId":"Eo3ISyIosZ","updatedAt":{"__type":"Date","iso":"2022-02-04T13:58:47.911Z"}})
Printing description of result.success:
▿ ParseCategory ({"objectId":"Eo3ISyIosZ","updatedAt":{"__type":"Date","iso":"2022-02-04T13:58:47.911Z"}})
  ▿ objectId : Optional<String>
    - some : "Eo3ISyIosZ"
  - createdAt : nil
  ▿ updatedAt : Optional<Date>
    ▿ some : 2022-02-04 13:58:47 +0000
      - timeIntervalSinceReferenceDate : 665675927.911
  - ACL : nil
  - originalData : nil
  - name : nil
  - index : nil
  - icon : nil
  - articles : nil

A category with this ID exists on the server. But when I print to the console, I see nil values for this category. Maybe I missed any update?

What’s the output when you query the relations:

You are absolutely right! This is a panel issue. I installed several versions, including beta, but the problem remained. I reset the cache on another browser, the entries are displayed once, after they disappear. But in the code, when requested, everything comes up correctly. This is strange, since I have several applications in this panel, in another application all relationships are displayed correctly.

A lot of time wasted. Thank you all for your help!

Should populate whenever you hit “refresh”. I recommend opening an issue on Parse Dashboard. You can reference this thread and with the GitHub comment I posted earlier. When describing the issue, it may help to do a screen recording of before refresh and after.

Certainly. I will do so. Today I will prepare all the data on this problem and send a description of the problem

1 Like

This should be fixed via #2275