I had performance issues due to converting a Document
to a Swift Object doing something like document["property"]??.doubleValue
for each property and property of embedded Documents. So I now figured out the best way to do this would probably be the Decodable
. So I tried:
let decoder = JSONDecoder()
do {
//let resultDocuments = try JSONSerialization.data(withJSONObject: resultDocuments, options: .prettyPrinted)
let model = try decoder.decode(Model, from: resultDocuments)
//print(model)
} catch {
print("error: \(error)")
}
Which fails to compile due to Cannot convert value of type 'Document' (aka 'Dictionary<String, Optional>') to expected argument type 'Data'
More context
From an aggregate call I receive a Document
from a
// collection was initialised from a Realm database
let resultDocuments = try await collection.aggregate(pipeline: somePipeline)
where the result is of type Document
:
/// A Dictionary object representing a `BSON` document.
public typealias Document = Dictionary<String, AnyBSON?>
The result looks like this:
[[
"example": Optional(RealmSwift.AnyBSON.double(1096.5171548657413)),
"subDocument": Optional(RealmSwift.AnyBSON.array([Optional(RealmSwift.AnyBSON.document([
"startTime": Optional(RealmSwift.AnyBSON.datetime(2023-01-22 07:39:44 +0000)),
"someKey": Optional(RealmSwift.AnyBSON.string("2DFB8488-7D7A-48CD-BCCE-652624BBCBF1")),
"coordinates": Optional(RealmSwift.AnyBSON.array([Optional(RealmSwift.AnyBSON.double(8.79564924822946)), Optional(RealmSwift.AnyBSON.double(47.498444215458825))])),
"subSubDocument": Optional(RealmSwift.AnyBSON.array([Optional(RealmSwift.AnyBSON.document([
"someOtherKey": Optional(RealmSwift.AnyBSON.string("0E425CE8-04C1-458A-87D3-7DE375EDBF50")),
"userName": Optional(RealmSwift.AnyBSON.string("ExampleName")),
"_id": Optional(RealmSwift.AnyBSON.string("63b3ed0f2e2d45e33bc992d3"))])
)])),
"_id": Optional(RealmSwift.AnyBSON.string("1C315817-A9FB-4360-84E9-834083851C33"))]))
])),
"_id": Optional(RealmSwift.AnyBSON.string("7a7a3b3b-85ab-435d-b1e9-ef13f17cf3c1")),
"someEvenDifferentProperty": Optional(RealmSwift.AnyBSON.string("A7394D67-4EE1-4490-9E36-99DB87FBCDEA")),
"example2": Optional(RealmSwift.AnyBSON.bool(false))]]
This is the Swift Decodable
object I want to convert the result to:
class Model: Identifiable, Equatable, ObservableObject, Decodable {
static func == (lhs: Model, rhs: Model) -> Bool {
lhs.id == rhs.id
}
var id: String
var subDocument: SubDocument?
var example: Double?
@Published var example2: Bool = false
enum CodingKeys: String, CodingKey {
case id = "_id"
case subDocument
case example
case example2
}
// this is needed because of @Published I believe
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
subDocument = try container.decode(SubDocument.self, forKey: .subDocument)
example = try container.decode(Double.self, forKey: .example)
example2 = try container.decode(Bool.self, forKey: .example2)
}
Then there is a subdocument that looks very similar and contains another SubSubDocument
, which only contains some String
s.
P.S. This question was asked after finding out the best way to achieve this would probably be to use a Codable
. See this question for reference.