Nested Queries in Realm. Swift - swift

I am trying to create nested queries in realm. I will paste my models in and explain what I mean.
Parent Model
#objcMembers class Group: Object {
dynamic var uuid: String = ""
dynamic var admin: User?
convenience init(uuid: String, admin: User) {
self.init()
self.uuid = uuid
self.admin = admin
}
}
Child Model
#objcMembers class Message: Object {
dynamic var uuid: String = ""
dynamic var group: Group?
dynamic var message: String = ""
convenience init(uuid: String, group: Group, from: User, message: String) {
self.init()
self.uuid = uuid
self.group = group
self.message = message
}
}
What I am trying to do is filter messages that are in a group with uuid x
All the answers I have seen are outdated.
What I have right now is
let result = RealmService.shared.realm.objects(Message.self).filter("group.uuid =
0E81CDEF-B63F-4DBE-9900-B486D40F4EC9")
What is the correct way of doing this?

Figured it out:
let result = RealmService.shared.realm.objects(Message.self).filter("group.uuid = '2C5E1738-1167-40CB-BE43-C415FD5E6E5D'")
Queried value has to be wrapped in ''

Related

Covert ObjectId to String SwiftUI Realm object

I have my model called Restaurant:
realm object on kotlin:
class Restaurant : RealmObject {
#PrimaryKey
var _id: ObjectId = ObjectId.create()
var name: String = ""
var adress: String? = null
}
I want to use the _id property. But for that I need to convert to a String in SwiftUI
I tried: restaurant_id as! String, it does not work,
Is is related to this post: https://www.mongodb.com/community/forums/t/swift-convert-objectid-to-string/121829
No real answers there
Any other solutions?
the error when using .toHexString(): Value of type 'any Library_baseObjectId' has no member 'toHexString':
the type of _id in this case:
The error when trying: "\(restaurant._id.stringValue)"
I solved this by adding a getter to the class:
class Restaurant : RealmObject {
#PrimaryKey
var _id: ObjectId = ObjectId.create()
var name: String = ""
var adress: String? = null
fun getID() : String{
return _id.toString()
}
}
ObjectID's in Swift have a stringvalue property which returns the ObjectID as a string
You could do this
let idAsAsString = someRealmObject._id.stringValue
Or for kotlin and other SDK;s
let idAsString = object._id.toString()
In SwiftUI, the id can be accessed in a similar way, and then use the value to init a new string
let x = someRealmObject._id.stringValue
let y = String(stringLiteral: x)
let _ = print(x, y)
Text("\(x) \(y)")
and the output will be
6376886a1dbb3c142318771c 6376886a1dbb3c142318771c
in the console and the same in the Text in the UI
Here's some SwiftUI showing the use
List {
ForEach(myModel) { model in
NavigationLink(destination: SecondView(navigationViewIsActive: $navigationViewIsActive, selectedEntryToShow: model))
{
Text("\(model._id.stringValue)") //ormodel._id.toString()
}
}
}
This Swift model works perfectly and the string of ObjectId can be read per above.
class Restaurant: Object {
#Persisted(primaryKey: true) var _id: ObjectId
#Persisted var name: String = ""
#Persisted var adress: String? = null
}

How to map a Firestore DocumentID to a RealmObject attribute?

I'm trying to provide some data in the cloud with Firestore that can be downloaded and stored in a Realm database on an iOS device.
The structure of my object that I want to store is:
import Foundation
import RealmSwift
import FirebaseFirestore
import FirebaseFirestoreSwift
#objcMembers class Flashcard: Object, Codable{
#objc dynamic var id: String? = NSUUID().uuidString
#objc dynamic var character: String?
#objc dynamic var title: String?
#objc dynamic var translation: String?
#objc dynamic var created: Date = Date()
let deck = LinkingObjects<FlashcardDeck>(fromType: FlashcardDeck.self, property: "cards")
override class func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case character
case translation
case created
case title
}
If I try to map the documentID to my id attribute with
#DocumentID #objc dynamic var id: String? = NSUUID().uuidString
If get the following error:
'Primary key property 'id' does not exist on object 'Flashcard'
How can I solve this problem?
EDIT: To make it more understandable here is a screenshot of my Firestore database:
The collection "PredifinedDecks" will store many decks. For example the id = DF59B1B3-BD22-47CE-81A6-04E7A274B98F represents one deck. Each deck will store an array/List with cards in it.
Not sure I fully understand the question but let me address this at a high level.
It appears there is a PredefinedDecks (a collection) that contains documents. Each document has a field (an array) of cards and some other field data. If the goal is to read in all of the documents (the decks) and their child data and store them as Realm objects, here's one solution. Start with a Realm object to hold the data from Firestore
class DeckClass: Object {
#objc dynamic var deck_id = ""
#objc dynamic var created = ""
#objc dynamic var title = ""
let cardList = List<CardClass>()
convenience init(withDoc: QueryDocumentSnapshot) {
self.init()
self.deck_id = withDoc.documentID
self.title = withDoc.get("title") as? String ?? "no title"
self.created = withDoc.get("created") as? String ?? "no date"
let cardArray = withDoc.get("cards") as? [String]
for card in cardArray {
let card = CardClass(withCard: card) {
self.cardList.append(card)
}
}
}
}
With this, you simply pass the documentSnapshot from Firestore for each document and the class will populate its properties accordingly.
and the code to read Firestore
func readDecks() {
let decksCollection = self.db.collection("PredefinedDecks")
decksCollection.getDocuments(completion: { documentSnapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
for doc in documentSnapshot!.documents {
let deck = DeckClass(withDoc: doc)
self.decksList.append(deck) //a Realm List class object? Something else?
}
})
}

Vapor 4: Children relation not eager loaded, use $ prefix to acces

Currently I am working on a school assignment where we have to build an API using Vapor. I have a few basic API calls working and I am trying a bit more advanced API calls now but I can't get this to work.
I have this function addToParty that is being called when the URL /party/join/:partyID is called with a body
{
"id": "CC1FAC6B-A2B3-471C-A488-147300196981",
"username": "string",
"is_ready": true
}
I am trying to find a party by the partyId and add the user to the list of users of the party.
func addToParty (req: Request) throws -> EventLoopFuture<Party.Output> {
guard let id = req.parameters.get("partyID", as: UUID.self) else {
throw Abort(.badRequest)
}
let input = try req.content.decode(Party.JoinParty.self)
return Party.find(id, on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { element in
element.users.append(User(id: UUID(input.id), username: input.username, is_ready: input.is_ready))
return element.save(on: req.db)
.map{ Party.Output(code: "200") }
}
}
When I try the code above I get the error Fatal error: Children relation not eager loaded, use $ prefix to access: Children<Party, User>(for: [party_id]): file FluentKit/Children.swift, line 33 from the line
element.users.append(User(id: UUID(input.id), username: input.username, is_ready: input.is_ready))
When I comment this line the code runs and I get a return code.
I tried adding the prefix to element.$users and $User but then it complains about not being able to find element.$users and $User in scope.
Party model
import Fluent
import Vapor
final class Party: Model, Content {
static let schema = "parties"
struct JoinParty: Content {
let id: String
let username: String
let is_ready: Bool
}
struct Output: Content {
let code: String
}
#ID(key: .id)
var id: UUID?
#Field(key: "party_code")
var party_code: String
#Field(key: "host_id")
var host_id: UUID
#Field(key: "is_active")
var is_active: Bool
// change to Game when model is made
#Field(key: "selected_games")
var selected_games: [String]?
// change to Setting when model is made
#Field(key: "settings")
var settings: String
#Field(key: "results")
var results: Array<GameResult>?
#Children(for: \.$party)
var users: [User]
init() { }
init(id: UUID? = nil,
party_code: String,
host_id: UUID,
is_active: Bool,
selected_games: [String]? = nil,
settings: String,
results: Array<GameResult>? = nil) {
self.id = id
self.party_code = party_code
self.host_id = host_id
self.is_active = is_active
self.selected_games = selected_games
self.settings = settings
self.results = results
}
}
User model
import Fluent
import Vapor
final class User: Model, Content {
static let schema = "users"
struct Input: Content {
let id: UUID
let username: String
}
struct Output: Content {
let id: String
let username: String
}
#ID(key: .id)
var id: UUID?
#Field(key: "username")
var username: String
#Field(key: "is_ready")
var is_ready: Bool
#OptionalParent(key: "party_id")
var party: Party?
#Children(for: \.$user)
var gameResults: [GameResult]
init() {}
init(id: UUID? = nil, username: String, is_ready: Bool, partyID: UUID? = nil) {
self.id = id
self.username = username
self.is_ready = is_ready
self.$party.id = partyID
}
}
I have a similar function to update a username from a user already working which is almost the same thing.
func update(req: Request) throws -> EventLoopFuture<User.Output> {
let input = try req.content.decode(User.Input.self)
return User.find(input.id, on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { user in
user.username = input.username
return user.save(on: req.db)
.map { User.Output(id: user.id!.uuidString, username: user.username) }
}
}
Any help would be really appreciated.
Thank you in advance.
Unfortunately, adding children to a parent model is not that intuitive yet. I hope that someday we can get that added, but it's not there yet. Fluent 5 maybe?
Anyway, what you'll need to do instead is create your new User model, passing in the party's ID value to the partyID initializer parameter, and then save the User model.
let user = User(id: UUID(input.id), username: input.username, is_ready: input.is_ready, partyID: element.id)
return user.save(on: request.db)
So your method should end up looking like this:
func addToParty(req: Request) throws -> EventLoopFuture<Party.Output> {
guard let id = req.parameters.get("partyID", as: UUID.self) else {
throw Abort(.badRequest)
}
let input = try req.content.decode(Party.JoinParty.self)
return Party.find(id, on: req.db).unwrap(or: Abort(.notFound)).flatMap { element in
return User(
id: UUID(input.id),
username: input.username,
is_ready: input.is_ready,
partyID: element.id
).save(on: req.db)
}.transform(to: Party.Output(code: "200"))
}

Realm Swift subclassing

I have two models that I am trying to subclass in swift using RealmSwift
Model 1: Users
#objcMembers class User: Object, Codable {
dynamic var id: Int = 0
dynamic var username: String = ""
dynamic var email: String = ""
dynamic var counts: Counts = Counts(follows: 0, followed_by: 0)
convenience init(id: Int, username: String, email: String, counts: Counts) {
self.init()
self.id = id
self.username = username
self.email = email
self.counts = counts
}
}
class Counts: Codable {
let follows: Int
let followed_by: Int
init(follows: Int, followed_by: Int) {
self.follows = follows
self.followed_by = followed_by
}
}
Here I created a model which inherits codable because I am using Swift 4 new decoding method. This model works fine. I can go add a user and read it fine. So doing this works fine:
let newUser = User(id: 1, username: "user1", email: "user1#gmail.com", counts: Counts(follows: 100, followed_by: 500000000))
RealmService.shared.write(newUser)
Now I am trying to create a model called Friend which has a field that inherits from User
Model 2: Friend
#objcMembers class Friend: Object {
dynamic var user: User = User(id: 0, username: "", email: "", counts: Counts(follows: 0, followed_by: 0))
dynamic var dateAdded: Date = Date(timeIntervalSinceNow: 0)
convenience init(user: User, dateAdded: Date = Date(timeIntervalSinceNow: 0)) {
self.init()
self.user = user
self.dateAdded = dateAdded
}
}
When I do this and load up my app I get a SIGBART and it highlights my initialization of realm : let realm = RealmService.shared.realm
When I remove my Friend Model the app works fine.
How do you properly subclass in Realm?
You cannot declare properties as normal Swift properties whose types are other Realm subclasses. What you are looking for is a many-to-one relationship.
Many-to-one relationships have to be declared optionals and you can't provide a default value
#objcMembers class Friend: Object {
dynamic var user: User?
dynamic var dateAdded: Date = Date()
convenience init(user: User, dateAdded: Date = Date()) {
self.init()
self.user = user
self.dateAdded = dateAdded
}
}
Unrelated, but when you want to create a Date object representing the current time, just call the default, empty initializer of Date, it will do that for you and it's much shorter than Date(timeIntervalSinceNow: 0).

Confusion why Realm LinkingObjects() isn't working :(

I have defined two very basic Object as follows:
class Language: Object {
dynamic var id: String = "" //"english", "chinese"
let versions = List<Version>()
convenience init(id: String, versions: [Version]) {
self.init()
self.id = id
self.versions.append(objectsIn: versions)
}
override static func primaryKey() -> String? {
return "id"
}
}
class Version: Object {
dynamic var id: String = "" //"kjv", "cus"
dynamic var name: String = "" //"Union Simplified"
let language = LinkingObjects(fromType: Language.self, property: "versions")
convenience init(id: String, name: String) {
self.init()
self.id = id
self.name = name
}
override static func primaryKey() -> String? {
return "id"
}
}
Every Language can have multiple Versions, and every Version has a reference (LinkingObject) to what Language holds it.
Next, I have the following code:
let kjvVersion = Version(id: "kjv", name: "King James Version")
let englishLanguage = Language(id: "english", versions: [kjvVersion])
print(kjvVersion)
Inspecting kjvVersion.language gives me back an empty LinkingObject array. Why?! What am I doing wrong here?
LinkingObjects objects contain the objects in the Realm which link to the containing object. Your objects are not managed by a Realm, so there will never be any objects in a Realm which link to them.