realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.46k stars 1.75k forks source link

Querying for objects with or without relationships #975

Closed kneth closed 9 years ago

kneth commented 9 years ago

It could be useful to be able to query for objects where relationships (RealmList<...>) are empty (or not empty).

Such a query could be:

RealmResults attachedTires = realm.where(RealmTire.class).equalTo("car", null).findAll();
cmelchior commented 9 years ago

The typesystem would have a hard time working with syntax like this because we have so many overloaded methods. Something like

RealmResults attachedTires = realm.where(RealmTire.class).isNull("car").findAll();

That would also generalize really well with null support.

vvictor10 commented 9 years ago

Sure, that should suffice.

Flydiverny commented 9 years ago

It seems this functionallity has been lost with the release of 0.83.0 as performing .isNull() on a relation (RealmList) now throws an exception saying RealmList isn't nullable. Is there any new way to check if theres any relationships or not?

kneth commented 9 years ago

A RealmList cannot be null - only have a zero length. Issue #1367 is tracking this. Even as it is labeled as P2, I think we will implement it soon.

Currently you have to iterate through your objects and check the length of your RealmList field.

astigsen commented 9 years ago

Core now has the ability to query on the number of elements in RealmLists, so it should be trivial to expose in the java query interface as well.

kneth commented 9 years ago

It is probably trivial to implement, but I am a bit worried about the API. The Java query interface is a fluent interface. The current link query syntax is (dogs is a RealmList):

realm.where(Owner.class).equalTo("dogs.name", "Fido").findAll();

Let us image we wish to find owner of two dogs. Using the current predicate functions, we could do

realm.where(Owner.class).equalTo("dogs", 2).findAll();

but it is hard to see that it is the number of objects in dogs we are querying (if the user actually thought dogs.age but mistyped, it is very hard to find that error). On the other hand, I don't think adding many more methods is a good idea:

realm.where(Owner.class).countEqualTo("dogs", 2).findAll();

and the mixture of a fluent interface and a query language is really bad:

realm.where(Owner.class).equalTo("count(dogs)", 2).findAll();
Flydiverny commented 9 years ago
realm.where(Owner.class).equalTo("dogs", 2).findAll();

While this looks nice I understand your concern, although I believe it has most potential for flexibility? Say you would like to find all Owners with at least 2 dogs

realm.where(Owner.class).greaterThanOrEqualTo("dogs", 2).findAll();

Adding more methods might be clearer for the user but that would end up with a lot of additional methods.

I agree mixing in count(xyz) feels bad, though if its for making things clearer then maybe its a worthwhile sacrifice?

Would it be possible to use a prefix method .count() like we have .not() ?

realm.where(Owner.class).count().equalTo("dogs", 2).findAll();

Though this might also be unclear.

astigsen commented 9 years ago

In Objective-C predicates, the count is just another property on the object (similar to how we use dot notation to traverse the object hierarchy), but they indicate that it is a computed property by prefixing it with @ (so you do "dogs.@count").

In java we could do the same, but I think it would be more natural to postfix it like a method to indicate that it is a computed property:

realm.where(Owner.class).equalTo("dogs.count()", 2).findAll();

It is pretty readable, and then we don't have to add any new methods.

Flydiverny commented 9 years ago

I like the idea of using @ for computed properties. But yes using .count() might feel more natural to java usage.

And using "dog.count()" feels pretty good to me, things like "dog.size" and "dog.size()" where among the first things I tried when trying to find a solution after isNull("dog") stopped working.