Regression when querying by reference in 2.2
See original GitHub issueDescribe the bug When your model contains references between two entities, sometimes you may want to query “reverse”, i.e. find all elements pointing to a certain reference. The naive approach would be something like:
var e2 = ds.find(Entity2.class).filter(Filters.eq("reference", e1)).first();
to find the first Entity2
having e1
as a reference. This works in 2.1.7, but fails in 2.2.0 and 2.2.1.
The query sent to the server in 2.1.7 looks like this:
{"find": "entity2", "filter": {"reference": "615563baccaef56a95890a4f", "_t": {"$in": ["Entity2"]}}, "limit": 1, "$db": "reference-test"}
This correctly resolves the requested entity.
In 2.2.1 the same code produces the following query:
{"find": "entity2", "filter": {"reference": {"_id": "615563baccaef56a95890a4f", "_t": "Entity1"}, "_t": {"$in": ["Entity2"]}}, "limit": 1, "$db": "reference-test", "lsid": {"id": {"$binary": {"base64": "EnVdYSopTsqExah54cEipw==", "subType": "04"}}}}
Most notably the reference
field in the filter contains the whole object e1
instead of the ID (as would be correct). This leads to the query failing.
To Reproduce Steps to reproduce the behavior:
Entity1.java
package referenceTest;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.IdGetter;
@Entity
public class Entity1{
@Id
private String _id;
@IdGetter
public String getId()
{
return _id;
}
}
Entity2.java
package referenceTest;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.IdGetter;
import dev.morphia.annotations.Reference;
@Entity
public class Entity2 {
@Reference(idOnly = true)
private Entity1 reference;
@Id
private String _id;
@IdGetter
public String getId()
{
return _id;
}
public Entity1 getReference() {
return reference;
}
public void setReference(Entity1 reference) {
this.reference = reference;
}
}
App.java
package referenceTest;
import com.mongodb.client.MongoClients;
import dev.morphia.Morphia;
import dev.morphia.query.experimental.filters.Filters;
public class App
{
public static void main( String[] args )
{
var mongoClient = MongoClients.create("<url>");
var ds = Morphia.createDatastore(mongoClient, "reference-test");
ds.getMapper().map(Entity1.class, Entity2.class);
ds.ensureIndexes();
// var e1_input = new Entity1();
// ds.save(e1_input);
// var e2_input = new Entity2();
// e2_input.setReference(e1_input);
// ds.save(e2_input);
var e1 = ds.find(Entity1.class).first();
var e2 = ds.find(Entity2.class).filter(Filters.eq("reference", e1)).first();
var e2_i = ds.find(Entity2.class).filter(Filters.eq("reference", e1.getId())).first();
System.out.println("e1: "+e1);
System.out.println("e2: "+e2);
System.out.println("e2_i: "+e2_i);
System.out.println("e2 == e2_i: " + (e2 != null && e2.getId().equals(e2_i.getId())));
}
}
- Compile and execute the program with the commented-out block active to create your data. In that case the lookup will succeed. (The
save()
calls seem to trigger something inside the DataStore, that causes the code to work correctly). - Re-compile and execute with the commented block in-active. The query for
e2
will fail. The query sent to the server will contain the whole object instead of only the ID.
Expected behavior
The query should behave the same way as in 2.1.7, i.e. the filter should query for the _id
of e1
, as the reference
-field in Entity2
is marked as @Reference(idOnly = true)
** Please complete the following information: **
- Server Version: 5.0.1
- Driver Version: 4.2.2
- Morphia Version: 2.2.1
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (4 by maintainers)
A new one since this one is already in a release. Thanks.
FYI, I just pushed 2.2.2 out to central. It would have been done days ago but my release script broke oddly and I just now fixed it. The sync should be done in an hour or two or four.