spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
75k stars 40.66k forks source link

Repository query is failing to filter documents on DBRef fields after spring boot upgrade. #20237

Closed tzeikob closed 4 years ago

tzeikob commented 4 years ago

Upgrading form spring boot version 2.1 to 2.2 and mongodb from 4.0.16 to 4.2.3 the query below is not working as it was before. When we provide the tenantId parameter the query is kind of ignoring this argument, returning an empty result. The tenant is actually a DBRef filed in another document called broadcast.

@Query(value = "{$and :["
            + "?#{ [0] == null ? { $where : 'true'} : { 'tenant.id' : [0] } },"
            + "?#{ [1] == null ? { $where : 'true'} : { 'status' : { $in: [1] } } },"
            + "?#{ [2] == null ? { $where : 'true'} : { 'sendAt' : { $lt: [2] } } },"
            + "?#{ [3] == null ? { $where : 'true'} : { 'type' :  [3] } },"
            + "?#{ [4] == null ? { $where : 'true'} : { 'sendAt' : { $gte: [4] } } }"
            + " ] }", count = true)
    public List<Broadcast> findByCriteria(String tenantId, List<String> status, Date sendBefore, String type, Date sendAfter, Pageable pageable);

Below you can find part of the broadcast class.

@Document(collection = "broadcasts")
@TypeAlias(value = "Broadcast")
@CompoundIndexes({
        @CompoundIndex(name = "status_sendAt", def = "{'status': 1, 'sendAt': 1}", background = true)
})
public class Broadcast {

    @Id
    private String id;

    private String label;

    @DBRef
    @Indexed(background = true)
    private Tenant tenant;

    @DBRef
    private List<Group> groups = new ArrayList<>();

    private BroadcastMethod method;

    private String text;

    private BroadcastType type;

    private String image;

    @Indexed(background = true)
    private BroadcastStatus status;
}

I have been testing directly to the database via mongo compass, filtering by the following context,

{"tenant.$id": ObjectId("5d9610d8dbcb1e0aaaf95eae")}

and this is working flawlessly, so I'm making the assumption that maybe something goes wrong with the latest version of spring boot mongo data (2.2.4) or the mongodb driver (3.11.2) itself.

bclozel commented 4 years ago

This might be a change in Spring Data MongoDB or MongoDB itself. Did you see something interesting in the bug tracker or in the new & noteworthy section?

Could you log the actual requests being sent to the database? Did you test the query directly against MongoDB 4.2.3?

A lot of things changed at once, so it's hard to pinpoint exactly what's going on. Maybe @christophstrobl has an idea?

christophstrobl commented 4 years ago

The issue might be related to DATAMONGO-1798 | DATAMONGO-1988. @tzeikob can you please open an issue in the Spring Data MongoDB bug tracker as @bclozel suggested and provide the code of Tenant or if you can an executable sample that reproduces the error.

bclozel commented 4 years ago

Thanks a lot @christophstrobl , I'll close this issue for now as this change probably didn't happen in this codebase directly. @tzeikob please let us know about this problem (a link to a new issue and a sample) in the comments here as well.

tzeikob commented 4 years ago

@christophstrobl @bclozel I found the root of the cause, changing the type of tenantId parameter from String to org.bson.types.ObjectId the query is now working as expected. I'm not sure if this is a bug, but I'll open a ticket in the bug tracker for further investigation.

 @Query(value = "{$and :["
            + "?#{ [0] == null ? { $where : 'true'} : { 'tenant.$id' : [0] } },"
            + "?#{ [1] == null ? { $where : 'true'} : { 'status' : { $in: [1] } } },"
            + "?#{ [2] == null ? { $where : 'true'} : { 'sendAt' : { $lt: [2] } } },"
            + "?#{ [3] == null ? { $where : 'true'} : { 'type' :  [3] } },"
            + "?#{ [4] == null ? { $where : 'true'} : { 'sendAt' : { $gte: [4] } } }"
            + " ] }", count = true)
    public List<Broadcast> findByCriteria(ObjectId tenantId, List<String> status, Date sendBefore, String type, Date sendAfter, Pageable pageable);