Based on the example below, Is it possible to query Profile based on two fields within a ``LinkingObjects, such as friendSent`? I have a profile type and a friend request type:
class Profile: Object {
// ...
@Persisted(originProperty: "sender") var friendSent: LinkingObjects<FriendRequest>
@Persisted(originProperty: "recipient") var friendRcvd: LinkingObjects<FriendRequest>
}
class FriendRequest: Object {
@Persisted var sender: Profile!
@Persisted var recipient: Profile!
@Persisted var status: RequestStatusEnum = .active
}
`
I'd then like to make a query for a `@ObservedResults(Profile.self) var users`
This nearly works, however, the individual clauses for `friendSent` and `friendRcvd` don't seem to be applied to only the same document. So I'm seeing the clauses for `$0.friendRcvd` evaluate to `true` if there exists a document where `.sender == profile` and one where `.status == .active`, but they aren't necessarily the same one.
Is it possible to write a query that requires those two filters to be applied to the same document?
Thanks!
I think the answer is āYesā but the formatting in the question make is challenging to read. Only the code should be code formatted - the rest of the text should not be.
Also, thereās a ``users` object in the question but we donāt know what that is.
The query in the question has a bunch of &&, meaning all of those statement must be true for the object to be returned, and, they all most be true on a single object. So the parens () are extraneous.
This code is puzzling
let friends_of_profile = users.where({ ($0.friendRcvd.sender
as $0 would be a user object, not a profile object. So the user object would have to have a Profile property to then reach the .sender property - like this
class User: Object {
@Persisted var friendRcvd: Profile
so is friendRcvd a property of User, Profile or something else?
Also LinkingObjects can contain one or more objects so naming the property as plural may help clarify the code. So instead of
friendSent: LinkingObjects<FriendRequest>
it would be better
friendsSent: LinkingObjects<FriendRequest>
I think the question needs editing and updating for clarity.
Sorry for the formatting problems- I didnāt get a chance to preview it during the posting process. It also looks like I canāt edit my post, so hereās it again:
Based on the example below, Is it possible to query Profile based on two fields within a LinkingObjects , such as friendSent? I have a profile type and a friend request type:
class Profile: Object {
// ...
@Persisted(originProperty: "sender") var friendSent: LinkingObjects<FriendRequest>
@Persisted(originProperty: "recipient") var friendRcvd: LinkingObjects<FriendRequest>
}
class FriendRequest: Object {
@Persisted var sender: Profile!
@Persisted var recipient: Profile!
@Persisted var status: RequestStatusEnum = .active
}
Iād then like to make a query for a @ObservedResults(Profile.self) var users
This nearly works, however, the individual clauses for friendSent and friendRcvd donāt seem to be applied to only the same document. So Iām seeing the clauses for $0.friendRcvd evaluate to true if there exists a document where .sender == profile and one where .status == .active, but they arenāt necessarily the same one.
Is it possible to write a query that requires those two filters to be applied to the same document?
Again, the query does not match the objects presented in the question
let friends_of_profile = users.where
Is querying the users collection - and each User class object would need to have a .friendRcvd and a .friendSent property. But there is no User object in the question.
More importantly the Profile Object LinkingObjects property are not ONE object - they are one or more objects.
Lastly, do you have a use case where the friendRcvd.sender and friendSent.recipient would be the same profile? That seems odd.
I specified the definition of users in my question - there is no users collection:
Apologies for the confusing naming. I also understand regarding the singular/plural naming of .friendRcvd as well.
So the query is looking for friends: profile A is a friend of profile B if A and B have both sent active FriendRequests to each other. Therefore, my query:
queries for profiles (within the full users set) where they have received active friend requests from profile and have sent active friend requests to profile.
However, my question proposed in my post still stands:
One issue may be an assumption of what this resolves to. Let me present an example
let a, b, c, d = 0
if ( a == 0 && b == 0) && ( c == 0 && d == 0) {
//do something if above is true
}
is equivalent to
if a == 0 && b == 0 && c == 0 && d == 0 {
//do something if above is true - note no () as it all must be true or if fails in either case.
}
The other thing when youāre doing a query like that, the query is an ANY query. In other words, return profiles that have ANY linked profile containing profile and ANY linked profile where status is active. I have still not fully wrapped my brain around the query though but I think you might run into circular references. Going to give this more thought and see if I can provide a better solution/answer.
I donāt believe thereās a way with the current schema. The issue is thereās too many back and forward references within the database to return more singular data. So the big picture is that itās returning results where the collection has ANY profiles that match and ANY status == .active.
One approach is to break out the invites into their own collection instead of trying to do it all in one. Itās somewhat denormalizing the data but will provide more granular access to specific data. Something like
InviteClass: Object {
@Persisted var whoWasInvited: User!
@Persisted var invitedByWho: User!
@Persisted var inviteCompletedDate: Date? // nil would mean the invite was not completed
}
I see- In this case, you could check just inviteCompletedDate != nil, which doesnāt suffer from the same ANY problem with a query.
Is there a way to write my original intended query using a standard MongoDB query, instead of the Realm interface? Iām wondering if this is a limitation of the interface or MongoDB itself.
Maybe? But the issue is how the schema is constructed.
When doing a query on a top level object about something in a LinkingObjects List, itās asking Realm/Mongo to return top level objects that have ANY x matching y in their List property.
If you want to query for more granular data, then you need to query on that data - like in my above example to then get which objects match exactly.
One issue is the size of the dataset. Realm objects are lazily loaded - meaning working with thousands (tens-of) requires very little memory as objects are only loaded when they are being worked with.
Creating a Union would require the objects to be loaded - possibly into an array - and that defeats the lazy-loadingness aspect. If the dataset is small, then yes, itās possible.
If the data set is large or will scale, then no, not a good idea as all of those objects could overwhelm the devices memory.
Also, subqueries are somewhat difficult to manage. I often find that during development it sounds like a great idea but more often than not, I end up ditching the subquery to implement something more straightforward- denormalizing the data per above pretty much gets around all of those issues.
That being said, I am not totally clear on what the results of the query should be. For example, I donāt understand in what use case the Recipient and Sender would be the same profile. If you look at the InviteClass above, it solves those issues. Hereās a sample query
Would it be possible to run two queries, one for finding āactiveā friend requests to Person A and then āactiveā friend requests from Person A. If these could be combined as one query, by union-ing two subqueries, then I could use .count ontop of that. That way this action could be performed directly on the FriendRequest data, instead of on the linking objects of Profile.
Again, āpossibleā leaves a lot of possibilities so yes, itās possible.
The issue is the schema setup - if you want to run a query for specific data in the FriendsRequest collection, run it against that collection, not a LinkingObjects property of another collection. If itās run against linking objects, it returns the top level model in the other collection where ANY in the linking objects is a match.
Here is your current model (from the initial question)
So something like
let results = realm.objects(FriendRequest.self).where { ($0.sender == personA || $0.recipient == personA) && $0.status == .active)
would return all active friend requests that were either initiated or received by personA.