You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The @MongoId annotation is not being taken into account for nested object queries using a projection class that doesn't include the nested object. This causes collection scans and results in query not finding the documents.
@SpringBootApplication@EnableMongoRepositoriespublicclassProjectionMongoIdApplicationimplementsCommandLineRunner {
@AutowiredMongoTemplatemongoTemplate;
@SuppressWarnings("resource")
publicstaticvoidmain(String[] args) {
SpringApplication.run(IndexIdMappingApplication.class, args);
}
@Overridepublicvoidrun(String... args) throwsException {
mongoTemplate.dropCollection(Widget.class);
IndexOperationsindexOps = mongoTemplate.indexOps(Widget.class);
indexOps.ensureIndex(newIndex("someRef._id", Direction.ASC));
mongoTemplate.save(newWidget("123", newSomeRef("a", "Apple")));
mongoTemplate.save(newWidget("456", newSomeRef("b", "Banana")));
// queries { "someRef._id" : "a"} and uses index for "someRef._id"mongoTemplate.find(newQuery(Criteria.where("someRef.id").is("a")), Widget.class).forEach(w -> {
System.out.printf("query by someRef.id found %s:%s\n", w.id, w.name);
});
// queries { "someRef._id" : "a"} and uses index for "someRef._id"mongoTemplate.find(newQuery(Criteria.where("someRef._id").is("a")), Widget.class).forEach(w -> {
System.out.printf("query by someRef._id found found %s:%s\n", w.id, w.name);
});
// queries { "someRef._id" : "a"} and uses index for "someRef._id"Queryquery = newQuery(Criteria.where("someRef.id").is("a"));
query.fields().include("name");
mongoTemplate.find(query, Widget.class).forEach(w -> {
System.out.printf("query by someRef.id w include fields found %s:%s\n", w.id, w.name);
});
// BUG: queries { "someRef.id" : "a"}, finds no doc, and results in a collection scan because it can't find index for "someRef.id"mongoTemplate.find(newQuery(Criteria.where("someRef.id").is("a")), WidgetProjection.class).forEach(w -> {
System.out.printf("query by someRef.id w projection class found %s:%s\n", w.id, w.name);
});
// queries { "someRef._id" : "a"} and uses index for "someRef._id"mongoTemplate.find(newQuery(Criteria.where("someRef._id").is("a")), WidgetProjection.class).forEach(w -> {
System.out.printf("query by someRef._id w projection class found %s:%s\n", w.id, w.name);
});
}
}
@DocumentclassWidget {
@IdStringid;
Stringname;
SomeRefsomeRef;
publicWidget(Stringid, SomeRefsomeRef) {
this.id = id;
this.name = "name-" + id;
this.someRef = someRef;
}
}
@Document(collection = "widget")
classWidgetProjection {
Stringid;
Stringname;
// SomeRef someRef; // Adding this makes it work but don't want it on the projection.
}
classSomeRef {
@MongoId(FieldType.IMPLICIT)
Stringid;
Stringname;
publicSomeRef(Stringid, Stringname) {
this.id = id;
this.name = name;
}
}
... find using query: { "someRef._id" : "a"} fields: Document{{}} for class: class Widget ...
query by someRef.id found 123:name-123
... find using query: { "someRef._id" : "a"} fields: Document{{}} for class: class Widget ...
query by someRef._id found found 123:name-123
... find using query: { "someRef._id" : "a"} fields: Document{{name=1}} for class: class Widget ...
query by someRef.id w include fields found 123:name-123
... find using query: { "someRef.id" : "a"} fields: Document{{}} for class: class WidgetProjection ...
^- BUG: using wrong id and no documents found and collection scan
... find using query: { "someRef._id" : "a"} fields: Document{{}} for class: class WidgetProjection ...
query by someRef._id w projection class found 123:name-123
Thank you for reaching out.
The snippet above works as designed. The query mapping is only able to use fields that are actually contained in the given domain type. WidgetProjection however does not contain the path to the property used in the criteria. Therefore it will treat the given input as is.
The fluent template API offers dedicated methods that allow to map the query against a given domain type and project results to a different one.
List<WidgetProjection> result = template.query(Widget.class)
.as(WidgetProjection.class)
.matching(where("someRef.id").is("a"))
.all();
Thank you for reaching out. The snippet above works as designed. The query mapping is only able to use fields that are actually contained in the given domain type. WidgetProjection however does not contain the path to the property used in the criteria. Therefore it will treat the given input as is.
That's unfortunate since it's not intuitive and seems to behave differently than the rest of the API. It seems like the mapping should work off of the collections domain type not the projections domain type. I'm assuming the problem for you is that there is no difference between those two; i.e., you only have the class/type passed to the find.
It might be more obvious/discoverable if there was an additional signature of:
/** equivalent to query(Class<T> domainType).as(Class<R> resultType).matching(CriteriaDefinition criteria) */
public <R> List<R> find(Query query, Class<?> entityClass, Class<R> resultType)
The
@MongoId
annotation is not being taken into account for nested object queries using a projection class that doesn't include the nested object. This causes collection scans and results in query not finding the documents.Actual:
{ "someRef.id" : "a"}
Expected:
{ "someRef._id" : "a"}
Using:
Example code:
Logging (logging.level.org.springframework.data.mongodb.core: DEBUG)
Profiling:
The text was updated successfully, but these errors were encountered: