带有Mongo @Query的Spring Data JPA不能在多个$ or条件下工作

时间:2018-10-20 23:27:53

标签: mongodb spring-data-jpa spring-data spring-data-mongodb

使用弹簧数据和mongodb的简单@Query有一个奇怪的问题,问题是当我使用多个$or条件时, 看来它不能同时使用2个或更多$or条件,或者我不能使其工作,它只能同时使用一个$or,而另一个则省略,我们可以在日志和最终结果集中看到它,其中日期($ or)之一未过滤:(

mongodb查询

db.getCollection('fileStorage').find({
    'user' : { '$ref' : 'user' , '$id' : ObjectId('5bafc1ab40005e285dbafadc')},
    'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('5bc0ca4336c9175f7ce6c91d')}},
    'completed' : true,
    'disabled' : false,
    $or : [
        { 'startDateTime' : null },
        { 'startDateTime' : { '$lte' : new Date() } }
    ],
    $or : [
        { 'endDateTime' : null },
        { 'endDateTime' : { '$gte' : new Date() } }
    ]
})

spring data jpa @Query

@Query("{ " +
    "'user' : {'$ref': 'user', '$id': ?#{[0]} }, " +
    "'businessCategory' : { '$ne' : {'$ref': 'businessCategory', '$id': ?#{[1]} } }, " +
    "'completed' : ?#{[2]}, " +
    "'disabled' : ?#{[3]}, " +
    "'$or' : [ { 'startDateTime' : null }, { 'startDateTime' : { '$lte' : ?#{[4]} } } ], " +
    "'$or' : [ { 'endDateTime'   : null }, { 'endDateTime'   : { '$gte' : ?#{[4]} } } ] " +
    "}")
List<FileStorage> getPlayList(ObjectId userId, ObjectId excludeBusinessCategory, boolean completed, boolean disabled, Date currentDateTime, Sort sort);

在日志中显示

find using query: 
{ "user" : { "$ref" : "user", "$id" : { "$oid" : "5bafc1ab40005e285dbafadc" } }, "businessCategory" : { "$ne" : { "$ref" : "businessCategory", "$id" : { "$oid" : "5bc0ca4336c9175f7ce6c91d" } } }, "completed" : true, "disabled" : false, "$or" : [{ "endDateTime" : null }, { "endDateTime" : { "$gte" : { "$date" : 1540077045932 } } }] }

在上面的日志中,我们看不到 startDateTime

"'$or' : [ { 'startDateTime' : null }, { 'startDateTime' : { '$lte' : ?#{[4]} } } ], " +

startDateTime以上的条件丢失.....

问题是我需要同时使用$ or,但同时只能使用一个,在上面的示例中,只能使用endDateTime

如果我评论endDateTime,它将开始与startDateTime一起使用,但对诸如此类的简单操作都不会起作用

"'$or' : [ {  } ], '$or' : [ {  } ],"

上面的$ or之一被省略了。...也许是故意的,我不知道如何使用它,我在Google和文档中找不到任何线索

我尝试很多事情都没有成功, 任何帮助都非常感谢,谢谢:)

更新#1 :我尝试了一种简单的存储库方法来显示问题

@使用2个$ or

进行查询
@Query("{" +
  " '$or' : [" +
  "      { 'completed' : null }," +
  "      { 'completed' : false }" +
  "  ]," +
  "  '$or' : [" +
  "      { 'disabled' : null }," +
  "      { 'disabled' : false }" +
  "  ]" +
  "}")
List<FileStorage> findTest();

@查询带有3个$ or

@Query("{" +
  " '$or' : [" +
  "      { 'completed' : null }," +
  "      { 'completed' : false }" +
  "  ]," +
  " '$or' : [" +
  "      { 'tested' : null }," +
  "      { 'tested' : false }" +
  "  ]," +
  "  '$or' : [" +
  "      { 'disabled' : null }," +
  "      { 'disabled' : false }" +
  "  ]" +
  "}")
List<FileStorage> findTest();

登录

find using query: { "$or" : [{ "disabled" : null }, { "disabled" : false }] } 

同样的问题。即使只有2个或多个简单$ or并且没有参数,同样的错误,它也仅使用一个$ or,其他$。消失.....

更新#2 :使用MongoTemplate和BasicQuery会发生问题吗? wtf

String stringQuery = String.format("{\n" +
  "  'user' : { '$ref' : 'user' , '$id' : ObjectId('%s')},\n" +
  "  'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('%s')}},\n" +
  "  'completed' : %b,\n" +
  "  'disabled' : %b,\n" +
  "  '$or' : [\n" +
  "    { 'startDateTime' : null },\n" +
  "    { 'startDateTime' : { '$lte' : new Date() } }\n" +
  "  ],\n" +
  "  '$or' : [\n" +
  "    { 'endDateTime' : null },\n" +
  "    { 'endDateTime' : { '$gte' : new Date() } }\n" +
  "  ]\n" +
  "}", userId, businessCategoryId, completed, disabled) ;
BasicQuery query = new BasicQuery(stringQuery);
files = mongoTemplate.find(query, FileStorage.class);

日志:削减startDateTime的相同问题

{ "user" : { "$ref" : "user", "$id" : { "$oid" : "5bafc1ab40005e285dbafadc" } }, "businessCategory" : { "$ne" : { "$ref" : "businessCategory", "$id" : { "$oid" : "5bc0ca4336c9175f7ce6c91d" } } }, "completed" : true, "disabled" : false, "$or" : [{ "endDateTime" : null }, { "endDateTime" : { "$gte" : { "$date" : 1540157706740 } } }] }

这个问题正在变成一个真正的难题...,发生的一切都是不同的和可能的方式,总是有相同的目的,spring数据不能使用一个以上的$ or,并且削减了一些没有任何理由的查询.......

更新#3

问题可能是由该图像解释的 其类似$ or是类似hashmap的键,最后一个 endDateTime 替换 startDateTime :(

在该图像中,我有4个索引键,当前的4是实数5,而我丢失了索引4,即startDateTime .........

请检查image1 here和image2 here我没有声誉 (发布图片至少需要10个声誉。)

enter image description here

更新#4

使用查询和条件进行斗争并在使用时发现新问题 一个或多个美元.........噩梦般的冒险还在继续

org.springframework.data.mongodb.InvalidMongoDbApiUsageException: Due to limitations of the com.mongodb.BasicDocument, you can't add a second '$or' expression specified as '$or

我找到了一种解决此问题的丑陋方法,将上面的查询与BasicQuery一起使用,它可以工作,但它的查询很la脚,充满了DRY,我真的不喜欢它,而且我知道有更好的方法这样做,Spring家伙真的很棒,而且我不相信mongo无法处理这种基本的查询

上面与BasicQuery一起使用的查询具有一个 $ or ,但是充满了重复的代码,可以完成此工作:(

查询x 4,可在所有条件下使用

db.getCollection('fileStorage').find({
'$or' : [
    {
        'user' : { '$ref' : 'user' , '$id' : ObjectId('5bafc1ab40005e285dbafadc')},
        'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('5bc0ca4336c9175f7ce6c91d')}},
        'completed' : true,
        'disabled' : false,
        'startDateTime' : { '$lte' : new Date() }, 
        'endDateTime' : { '$gte' : new Date() }
    },
    {
        'user' : { '$ref' : 'user' , '$id' : ObjectId('5bafc1ab40005e285dbafadc')},
        'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('5bc0ca4336c9175f7ce6c91d')}},
        'completed' : true,
        'disabled' : false,
        'startDateTime' : null,
        'endDateTime' : null        
    },
    {
        'user' : { '$ref' : 'user' , '$id' : ObjectId('5bafc1ab40005e285dbafadc')},
        'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('5bc0ca4336c9175f7ce6c91d')}},
        'completed' : true,
        'disabled' : false,
        'startDateTime' : { '$lte' : new Date() }, 
        'endDateTime' : null
    },
    {
        'user' : { '$ref' : 'user' , '$id' : ObjectId('5bafc1ab40005e285dbafadc')},
        'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('5bc0ca4336c9175f7ce6c91d')}},
        'completed' : true,
        'disabled' : false,
        'startDateTime' : null, 
        'endDateTime' : { '$gte' : new Date() }
    }    
    ] 
})

带有2个查询的代码,仅作为示例

String stringQuery = String.format("{\n" +
  "'$or' : [{" +
  "  'user' : { '$ref' : 'user' , '$id' : ObjectId('" + userId + "')}," +
  "  'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('" + businessCategoryId + "')}}," +
  "  'completed' : " + completed + "," +
  "  'disabled' : " + disabled + "," +
  "  'startDateTime' : { '$lte' : new Date() }," +
  "  'endDateTime' : { '$gte' : new Date() }" +
  "}," +
  "{" +
  "  'user' : { '$ref' : 'user' , '$id' : ObjectId('" + userId + "')}," +
  "  'businessCategory' : { '$ne' : { '$ref' : 'businessCategory', '$id' : ObjectId('" + businessCategoryId + "')}}," +
  "  'completed' : " + completed + "," +
  "  'disabled' : " + disabled + "," +
  "  'startDateTime' : null," +
  "  'endDateTime' : null" +
  "}]" +
  "}", userId, businessCategoryId, completed, disabled);

BasicQuery basicQuery = new BasicQuery(stringQuery/*, "{ user : 1, businessCategory : 1}"*/);
files = mongoTemplate.find(basicQuery, FileStorage.class);

日志

{ "$or" : [{ "user" : { "$ref" : "user", "$id" : { "$oid" : "5bafc1ab40005e285dbafadc" } }, "businessCategory" : { "$ne" : { "$ref" : "businessCategory", "$id" : { "$oid" : "5bc0ca4336c9175f7ce6c91d" } } }, "completed" : true, "disabled" : false, "startDateTime" : { "$lte" : { "$date" : 1540249026648 } }, "endDateTime" : { "$gte" : { "$date" : 1540249026648 } } }, { "user" : { "$ref" : "user", "$id" : { "$oid" : "5bafc1ab40005e285dbafadc" } }, "businessCategory" : { "$ne" : { "$ref" : "businessCategory", "$id" : { "$oid" : "5bc0ca4336c9175f7ce6c91d" } } }, "completed" : true, "disabled" : false, "startDateTime" : null, "endDateTime" : null }] }

明天我尝试清理代码并发布结论.....我不太喜欢该代码...

但是太奇怪了,我们可以在spring data mongo中使用原始查询,太奇怪了!!! 也许我不知道该怎么做

2 个答案:

答案 0 :(得分:0)

您是否确实尝试获取与诸如“用户”:“ somevalue”和“ businessCategory”:“ somevalue”之类的设置条件匹配的文档,并且{“ startdate”为空或小于当前日期时间}和{ “ enddate”为null或大于当前日期时间}如果查询注释不起作用。 尝试在java方法本身中使用来自spring data mongo的Criteria和Query类。我只是想知道以下内容是否对您有用。 如果是,那么您可以在第一个条件本身中与Or一起使用,以查看是否可以将其本身组合在一起,而不是编写其他条件然后使用OrOperator

    @Autowired
    private MongoOperations cosmosTemplate;

 List<Criteria> citerion = new ArrayList<>();
Criteria criteria = new Criteria();

    criteria = Criteria.where("User")
                    .is("somevalue")
                    .and("businessCategory")                
                    .is("somevalue")
                    .and("completed")
                    .is("somevalue")
                    .and("disbaled")
                    .is("somevalue")
                    .and("startDateTime")
                    .is(null);

       criterion.add(criteria);

       criteria = Criteria.where("User")
                    .is("somevalue")
                    .and("businessCategory")                
                    .is("somevalue")
                    .and("completed")
                    .is("somevalue")
                    .and("disbaled")
                    .is("somevalue")
                    .and("startDateTime")
                    .lte("somedate");

           criterion.add(criteria);



        Query query = Query.query(new Criteria().orOperator(citerion.toArray(new Criteria[citerion.size()]))).with(new Sort(Sort.Direction.ASC,"user"));
         return mongoTemplate.find(queryuery, <<yourclass>>.class);

答案 1 :(得分:0)

对我来说,它使“和”变得明确,就像这样:

            "{" + //
            "  '$and': [" + //
            "    { 'status': ?0 }," + //
            "    { 'publishedFrom': { $lte: ?1 } }," + //
            "    { '$or': [" + //
            "      { 'publishedUntil': null }," + //
            "      { 'publishedUntil': { $gte: ?1 } }" + //
            "    ] }," + //
            "    { 'interests': { $in: ?2 } }," + //
            "    { '$or': [" + //
            "      { 'tenantNumbers': { $size: 0 } }," + //
            "      { 'tenantNumbers': { $in: ?3 } }" + //
            "    ] }" + //
            "  ]" + //
            "}"