Right way to reorder embedded arrays

hey everyone,

I try to implement a spreadsheet-like table with swift, realm and mongodb. My goal is to build a table with multiuser access and make it possible for the users to reorder columns and rows via drag and drop - and true offline first – all functions should work offline too and data should be consistent after a later sync with other users.

My idea is to have a table object collection that has two embedded arrays that store the ids for the cells and represent the row order and the column order. Moreover the table object has an embedded array with the rowobjects that contains an embedded array for the columns. When the UI-Tableview is loaded, I could look up the “position” of the data in the the two “order” arrays. When reordering the rows and columns via drag and drop I could just reorder the ids in the corresponding row or column order array.

I wanted to try this out with a table that allows users to reorder only the rows via drag and drop. (all CRUD operations are implemented, sync too – everything works fine here)

This is the realm schema of the table:


{
  "properties": {
    "_id": {
      "bsonType": "string"
    },
    "_partition": {
      "bsonType": "string"
    },
    "smartListRowIDs": {
      "bsonType": "array",
      "items": {
        "bsonType": "object",
        "properties": {
          "rowID": {
            "bsonType": "string"
          }
        },
        "required": [
          "rowID"
        ],
        "title": "OrderObject"
      }
    },
    "rowObjects": {
      "bsonType": "array",
      "items": {
        "bsonType": "object",
        "properties": {
          "owner": {
            "bsonType": "string"
          },
          "comment": {
            "bsonType": "string"
          },
          "rowID": {
            "bsonType": "string"
          },
          "cellObjects": {
            "bsonType": "array",
            "items": {
              "bsonType": "object",
              "properties": {
                "stringValue": {
                  "bsonType": "string"
                },
                "columnPosition": {
                  "bsonType": "int"
                }
              },
              "required": [
                "stringValue",
                "columnPosition"
              ],
              "title": "CellObject"
            }
          }
        },
        "required": [
          "comment",
          "owner",
          "rwoID"
        ],
        "title": "RowObject"
      }
    },
    "name": {
      "bsonType": "string"
    },
    "owner": {
      "bsonType": "string"
    }
  },
  "required": [
    "_id",
    "_partition",
    "name",
    "owner"
  ],
  "title": "SmartList"
}

And here are the swift models:


class SmartList: Object {
   
    @objc dynamic var _id: String = UUID().uuidString
    @objc dynamic var _partition: String = ""
    @objc dynamic var name: String = ""
    @objc dynamic var owner: String = ""
    let rowObjects =  RealmSwift.List<RowObject>()
    let smartListRowIDs =  RealmSwift.List<OrderObject>()
    
    override static func primaryKey() -String? {
        return "_id"
    }
    
    
    convenience init(ownerName:String, tableName:String, partition:String) {
        self.init()
        self._partition = partition
        self.name = tableName
        self.owner = ownerName
    }
}

class OrderObject: EmbeddedObject {
    @objc dynamic var shotID:String = ""
    
    convenience init(rowID:String) {
        self.init()
        self.rowID = rowID
    }
}


class RowObject: EmbeddedObject {

    @objc dynamic var comment: String = ""
    @objc dynamic var owner: String = ""
    @objc dynamic var rowID:String = "" 
    let cellObjects =  RealmSwift.List<CellObject>()
    
    convenience init(comment:String, ownerName:String,rowID:String) {
        self.init()
        self.comment = comment
        self.owner = ownerName
        self.rowID = rowID
       
    }
}

class CellObject: EmbeddedObject {
    @objc dynamic var stringValue:String = ""
    @objc dynamic var columnPosition: Int = 0
    
    convenience init(stringValue:String,columnPosition:Int) {
        self.init()
        self.stringValue = stringValue
        self.columnPosition = columnPosition
    }
}

When reordering the table rows via drag and drop, I move the OrderObject from the old position to the new position in the smartListRowIDs-list and update the tableview-data.

try! self.smartListRealm.write {         
    smartList?.smartListRowIDs.move(from: oldRow, to: newRow)
}

Everything works fine when one or more user work on the same table online, insert rows, delete rows, reorder it via drag and drop and so on. But when one user is offline and another is online and both user delete different rows, insert new data, and drag and drop, the smartListRowIDs-list gets totally mixed and corrupted after resyncing the offline user: there are empty entries in the list and the order of the data is different for both users after the sync.

I wonder if my concept and the schemas are wrong for this use case? Am’I missing something fundamental?

Thanks in advance!