简体   繁体   中英

Can the MongoDB Realm Swift API still just insert a struct into an Atlas collection, like in Stitch?

I have a hierarchy of codable Swift structs that I need to store in MongoDB in the cloud (Atlas). I do not need to persist these structs locally, and this app won't need to access this data once it's stored. (There are other apps accessing it, but that's out of the scope of this question.)

MongoDB used to provide a solution called Stitch that did allow me to do just that: my iOS app had a codable Swift struct, the iOS app connected to a Stitch app on MongoDB's Atlas cloud, and I was able to insert the struct into a collection in the DB.

With Stitch, I was able to just do it like this:

let itemsCollection = mongoServiceClient.db(“myDatabase”).collection(“myCollection”,
    withCollectionType: MyStruct.self)
itemsCollection.insertOne(myStruct) 

Now Stitch is apparently deprecated and replaced by Realm, a formerly-third-party local persistency layer that MongoDB acquired and integrated with their Atlas cloud.

Realm isn't backwards-compatible with Stitch, and it no longer seems to be able to map Swift structs to a MongoDB backend: it can now sync Realm objects, ie ObjC-bridged subclasses of an abstract base class that Realm defines. Converting dozens of structs that my app uses in multiple places into such classes would be way too involved, especially since I would only do that for the sole purpose of uploading them to a backend as I do not need any of the (no doubt excellent) core functionalities of Realm.

(By the way, I find the migration from structs to objects, especially with an Objective-C foundation, quite baffling, as it goes very much against the flow: it's quite clear that Swift and value types are the future for Apple's platforms...)

My question : is there a way I may have missed to just connect to a Realm app on Atlas, and insert documents defined as Swift structs into a collection in an Atlas DB?

Or is there a reasonably-easy way to convert JSON into a Realm object? From what I read, I'd still need to define a schema for the object, and since my source struct contains several embedded structs, it would require creating Object subclasses for each, which is something I'd really need to avoid. Basically, I designed this functionality of my app around MongoDB and Stitch, and I'm not ready to suddenly accommodate the limitations of Realm for no added value.

Finally, failing all that, is there a way to encode my structs into a format that some official MongoDB API (eg Realm) can use for inserting?

I can already encode my struct into JSON, but that doesn't seem to be enough. I have seen the doc about MongoDB Realm Remote Access , but it doesn't say anything about my use case beyond connecting to a DB.

Error messages I get suggest that I would need to create a Document (aka Dictionary<String, Optional<AnyBSON>> ), where AnyBSON is an enum that defines the type of the BSON value. I haven't found any documentation about converting anything into that format: is there an API for that, or do I need to break down my struct or JSON into a hierarchy of AnyBSON values?

I'll preface this answer by stating it's not a specific answer but more guidance on how to accomplish what's asked in the question.

First, let me re-state the question

What is the process to insert data into MongoDB Realm without storing it locally or using Realm objects; use Classes, Structs (or something else) instead.

To illustrate, we have some tasks stored in MongoDB Realm (Atlas) with nothing stored locally. Here I will create a Document that contains task information and insert it.

We first need to define where the data will be stored and what collection to store it in:

let app = Your App
let client = app.currentUser!.mongoClient("mongodb-atlas")
let database = client.database(named: "task-database")
let collection = database.collection(withName: "TaskClass")

then we'll create some BSON's to store the textual data in

let _id = AnyBSON(ObjectId.generate())
let taskName = AnyBSON(stringLiteral: "Inserted Task")
let status = AnyBSON(stringLiteral: "Open")
let partition = AnyBSON(stringLiteral: Constants.REALM_PARTITION_VALUE)

then, for each BSON, give each a key: value pair (Dictionary)

let idDict = ("_id", _id)
let taskDict = ("name", taskName )
let statusDict = ("status", status)
let partitionDict = ("_partitionKey", partition)'

finally we'll create and write a Document to MongoDB Realm

let myTaskDoc = Document(dictionaryLiteral: idDict, taskDict, statusDict, partitionDict)

collection.insertOne(myTaskDoc, { result in
    print(result)
})

The above code answers the question

Can the MongoDB Realm Swift API still just insert a struct into an Atlas collection, like in Stitch?

Yes. In fact I did it without using a Struct at all. Keeping in mind the above code is really for simplicity - obviously leveraging Structs or Classes will provide a lot more flexibility and encapsulation of your data. This would be accomplished by crafting or updating an existing class or struct so when data is to be written utilize a function to set up the properties in AnyBSON format and return a Document.

class TaskClass {
   var name = ""

   func toBson() -> Document {
       let taskName = AnyBSON(stringLiteral: self.name)
       let taskDict = ("name", taskName )
       let myTaskDoc = Document(dictionaryLiteral: taskDict) //abbreviated
       return myTaskDoc
}

then to use

let doc = myTask.toBson()
collection.insertOne(doc, { result in
   print(result)
})

This could easily be expanded on using Codable and JSONEncoder() to directly store JSON data in your structs, and then send BSON data to the server

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM