Realm how to write subquery - swift

I am study about Realm db, this db is nice as compare with core data but I am stuck on one place as follows:
I have two RLMObject in that I created relationship and I want to run join query (sub query) on that, but I can't do that.
first object (table) in Ralm
class Dog : RLMObject
{
dynamic var name = ""
dynamic var age = 0
// create variable of Owner object
dynamic var owner = RLMArray(objectClassName: "Owner")
override class func primaryKey() -> String!{
return "name"
}
}
second object (table) in Ralm
class Owner : RLMObject{
dynamic var myName = ""
}
so I want to fetch only those Dog names which belong with owner name 'ram'
I tried following sub query
var dog = Dog.allObjects().objectsWithPredicate(NSPredicate(format:"SUBQUERY(Owner, $owner, $owner.myName = 'ram')", argumentArray: nil))
but app is crashing with following error
RealTest[1701:17960] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "SUBQUERY(owner, $owner, $owner.myName = 'ram')"'
also I search it on net I found that realm.objects but it gave me error about not found.
Thanks in advance!

Your predicate should look like this:
let predicate = NSPredicate(format:"SUBQUERY(Owner, $owner, $owner.myName = 'ram') .#count > 0", argumentArray: nil)
The idea here is to make sure you add .# count > 0 at the end, as the predicate needs to return true or false for it to work.

This can be achieved using a query like:
Dog.allObjects().objectsWhere("ANY owner.myName = 'ram'")
SUBQUERY is only necessary if you have multiple constraints on the target of the relationship that must all be fulfilled by a single row, or if you wish to express a constraint other than ANY / ALL / NONE on the number of rows that match.
That said, as of Realm Objective-C and Swift 0.98.0 SUBQUERY is now supported.

While Realm supports filtering objects via NSPredicate, at this time of writing, Realm's implementation of NSPredicate yet support every single type of keyword that the native Apple frameworks do, including SUBQUERY. Realm provides an NSPredicate cheat sheet on its website, outlining which types of queries it presently supports.
That being said, if you already have an Owner object at this point, you can actually use another Realm method on the Owner object ([RLMObject linkingObjectsOfClass:forProperty:]) to find out which Dog objects are referencing it.
Finally, that realm.objects error is because that syntax is from the native Swift version of Realm, and the code you're using here is the Objective-C version of Realm, bridged over to Swift.
Let me know if you need any more clarification!

Related

Realm Migration - Changing Name of Class (for complex class)

I'm not able to change the class name of a Realm Object that has properties pointing to other Realm Objects. A class like this, for example.
class OldClass: Object {
var id: String!
var dog: Dog! //this is a Realm Object (with its own table)
}
I've seen the simple examples of how to do this.
migration.enumerateObjects(ofType: "OldClass", { (oldObject, newObject) in
migration.create("NewClass", value: oldObject!)
})
I expect the above would work if the schemas for both OldClass and NewClass were the same, AND if all the properties were non-Realm objects. If the schemas are different, I've gathered that you can do something like this.
migration.enumerateObjects(ofType: "OldClass", { (oldObject, newObject) in
let obj = migration.create("NewClass")
obj["id"] = (oldObject["id"] as! String)
obj["newPropertyName"] = (oldObject!["oldPropertyName"] as! Int)
})
Neither of these example seem to work when your object has a property pointing to another Realm object though. At least this is what I suspect, since I get RLMException 'Can't create object with existing primary key value'.
My suspicion is that the 'existing primary key' is referring to the Dog object, and that in migrating from NewClass to OldClass, the migration is trying to re-create the Dog object (which already exists).
How do I properly perform this type of migration?
Unfortunately this feature is not implemented, we track it in https://github.com/realm/realm-cocoa/issues/2162. You can also find some useful info at https://github.com/realm/realm-cocoa/issues/4366.

How to get the values from Realm List to be used in a UITableview

Using the (modified) examples in the Realm Swift documentation:
class Dog: Object {
dynamic var name = ""
dynamic var age = 0
let puppies = List<Puppies>()
}
class Person: Object {
dynamic var name = ""
dynamic var picture: NSData? = nil // optionals supported
let dogs = List<Dog>()
}
class Puppies: Object {
dynamic var name = ""
}
Let's assume that the Person.name = Bob, and that Bob has several dogs added to his dogs List. I have added another model class called Puppies, which would represent puppies that belong to Bob's dogs. (Apparently Bob owns a kennel.)
How would I get the values to display the names of Bob's dogs and the number of puppies belonging to each dog in a UITableview?
More specifically, what is the code to extract the property values of the List of dogs that belong to Bob. I assume that once I get those values it won't be difficult to list them in the tableview cells.
I decide to use the slightly modified example from the documentation instead of my own code so that those who read this won't have to try and interpret my code, and be able to focus on the solution.
I have been able to save my data and believe I have made the relationships between the objects link properly, but don't know how to get the values of the List objects, based on the primary key I have in my top level model. The problem I have is that (using the example above): the puppies know what dog they belong to, and the dog knows the person it belongs to, but the inverse relationships don't seem to work.
(By the way; I used the LinkingObject examples in the documentation in a playground and it throws and error. I'm not sure if the examples are incomplete in some way.)
In the Realm Browser (displaying the Person object) I can see the data as entered but the link that shows [Dog] has a 0 next to it and when I click on the link, the table that shows is blank. Maybe solving that issues will be the answer to make everything else work.
Please excuse my ignorance. I'm still learning.
Thanks to Ahmad F. for pointing me in the right direction.
Here is the answer:
I did not know how to append to the list property in each of the object classes. Following the example above, it is done by creating a variable that holds the Person object. Then the realm.write function would look something like this.
newDog = Dog()
newDog.name = "Phydeaux"
.....
try! realm.write {
currentPerson?.dogs.append(newDog)

Parse local datastore relation

I've a class called category, and I have retrieved my categories from local datastore through query.getFromLocalDataStore().
Next I've the following code
var userExpense = PFObject(className: "Expenses")
userExpense["category"] = category
userExpense.saveEventually()
userExpense.pin()
And now i'm getting this error,
{error={"__type":"Pointer","className":"Category","localId":"local_55876b12913120b9"} is not a valid Pointer, code=106}
Any idea why? I wanted
If I'm correct, you downloaded the category variable as a PFObject, not as a pointer. What you can do, is to create a pointer from your category with the method:
objectWithoutDataWithClassName:objectId:
and set that to userExpense["category"], and that will be a valid pointer.

MongoDB C# - update using custom strongly-typed objects not allowed?

I am trying to perform an update using strongly-typed objects. For example,
public void setAppointmentPrefs(string UserName, IEnumerable<AppointmentInfo> info)
{
var query = new QueryDocument {{ "ProviderId", UserName}};
var update = Update.Set("Prefs",prefs); // prefs.toList() gives same error
// providerprefs initialized in constructor
providerprefs.Update(query, update);
}
I receive a compiler error saying:Error 14 The best overloaded method match for 'MongoDB.Driver.Builders.Update.Set(string, MongoDB.Bson.BsonValue)' has some invalid arguments
Obviously the Mongo driver will not let me update based on my own object (whether as IEnumerable or prefs.toList()), which seems a contrast from the way it permits me to insert or query with custom objects. Surely I am missing something obvious that would permit me to avoid deserializing, weakly typing then creating a generic BsonDocument!! TIA.
You can do an Update based on your own types! Have you tried using the typed Query and Update builders?
Try something like this:
var query = Query<AppointmentInfo>.EQ(i => i.ProviderId, userName);
var update = Update<AppointmentInfo>.Set(i => i.Prefs, info.Prefs);
Not sure I got the types and everything write from your partial code, but that should give you the general idea.
Let me know if you have any further questions.
I know this has been answered but I for one don't fully understand Roberts answer.
All I did is call the "ToBsonDocument()" method for it to except the object as a parameter
So:
customObject.ToBsonDocument()
If you have an array of objects inside a document:
var query = Query.EQ("_id", ObjectId.Parse(id.ToString()));
var update = Update.Push("ArrayOfObjects", customObject.ToBsonDocument());
collection.Update(query, update);

EF1: Filtering derived types of entity class using .OfType<> by passing a string value

I have a situation where I'm trying to filter a LINQ select using a derived sub class.
ctx.BaseEntity.OfType<SubClass>() - this works fine.
However I'd like to do this using a string value instead. I've come across a performance barrier when I have lots (>20) Sub Classes and selecting an Entity without using OfType just isn't an option. I have a generic UI that renders from the base class, so I don't know what Class Type will be returned at compile time.
So what I'd like to do is this:
Perform a projected Select where I
return just the SubClassType from
the database
Perform a second select
using this value as the OfType to
only select the relevant related
entity from the database (No mass
unions generated)
int id = 1;
var classType = (from c in ctx.BaseClass.Include("ClassType")
where c.id == id
select new
{
c.ClassType.TypeName
}).First();
BaseClass caseQuery = ctx.BaseClass.OfType<classType.TypeName>()
.Include("ClassType")
.Include("ChildEntity1")
.Include("ChildEntity2")
.Where(x => x.id== id);
But obviously this won't work because OfType requires a Type and not a string.
Any ideas on how I can achieve this?
Update:
As a side note to the original question, it turns out that the moment you project a query that uses a Navigation Property - it builds the monster SQL too, so I've ended up using a stored procedure to populate my ClassType entity from the BaseClass Id.
So I've just got it to work using eSQL, which I'd never used before. I've posted the code here just in case it helps someone. Has anyone else got a more strongly typed solution they can think of?
BaseClass caseQuery = ctx.BaseClass.CreateQuery<BaseClass>("SELECT VALUE c FROM OFTYPE(Entities.[BaseClass],namespace.[" + classType.TypeName + "]) as c")
.Include("ClassType")
.Include("ChildEntity1")
.Include("ChildEntity2")
.Where(x => x.id== id).FirstOrDefault();
To answer the headline question about calling OfType with a string / runtime type, you can do the following:
// Get the type, assuming the derived type is defined in the same assembly
// as the base class and you have the type name as a string
var typeToFilter = typeof(BaseClass)
.Assembly
.GetType("Namespace." + derivedTypeName);
// The use reflection to get the OfType method and call it directly
MethodInfo ofType = typeof(Queryable).GetMethod("OfType");
MethodInfo ofTypeGeneric = method.MakeGenericMethod(new Type[] { typeToFilter });
var result = (IQueryable<Equipment>)generic.Invoke(null, new object[] { equipment });
Combine this with your stored procedure to get the class name and you (should?) avoid the massive join - I don't have table-per-type implementation to play with so I can't test.