【问题标题】:Spring Data MongoDb @Query won't work with more than one $or conditionsSpring Data MongoDb @Query 不适用于多个 $or 条件
【发布时间】:2019-03-25 10:34:39
【问题描述】:

我有一个带有spring数据和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 之一被简单地省略了......也许它是故意的,我不知道如何使用它,我在谷歌和文档中找不到任何关于它的线索

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

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

@Query with 2 $or

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

@Query with 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,其他(s)消失.....

UPDATE #2:使用 MongoTemplate 和 BasicQuery 时,问题发生在???????呵呵

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 } } }] }

这个问题正在变成一个真正的痛苦......,发生的一切都是不同的和可能的方式,总是有相同的结束,弹簧数据不会与超过一个 $or 一起工作,它会削减一些无缘无故的查询......

更新 #3

也许问题是由该图像解释的 它的like $or是like hashmap的key,最后一个endDateTime代替了startDateTime :(

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

请检查 image1 here 和 image2 here 我没有声望 (您需要至少 10 声望才能发布图片。)

enter image description here

更新 #4

在与 Queries and Criterias 战斗后,使用时发现新问题 不止一个美元或............噩梦般的冒险还在继续嘿嘿嘿

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 一起使用,它可以工作,但它是一个蹩脚的查询,充满了 DRY,我真的不喜欢它,我知道有更好的方法这样做,春天的家伙真的很棒,我不相信 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 x 查询,只是一个示例

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中使用原始查询太奇怪了,太奇怪了!!!! 或者我不知道该怎么做

【问题讨论】:

  • 你到底想用多个 OR 语句来完成什么?您可以将它们全部合并到一个 OR 中吗?
  • 感谢@hary,我正在尝试在我的帖子中进行类似上述查询的简单查询,其工作方式与 mongo 控制台中的预期一样,这是获取开始和结束日期的唯一方法,在数据范围,并且当未定义日期(均为空或其中一个)时,因此我必须在查询中为每个日期使用两个 $or's,我失去了几个小时的“战斗”,而弹簧数据总是丢失一个$或者在这个过程中,奇怪的是,我尝试了很多东西,现在我尝试了 MongoTemplate (update #2),我不相信,但它也削减了 startDateTime !!!!
  • 你能将它们全部合并到一个 OR 中吗?我尝试一下,合并两者,它不会工作它是一个简单的查询,如果我合并它找到所有 4 个条件并且结果不起作用,如果我合并,日期范围根本不起作用,上面的相同查询返回5 条记录,而不是 2 条......

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


【解决方案1】:

您是否正在尝试获取符合设置条件的文档,例如“user”:“somevalue”AND“businessCategory”:“somevalue”AND {“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);

【讨论】:

  • 谢谢@Hary,我现在正在工作,但我会尽快尝试像您建议的 4 种不同的方法。我昨天再次阅读了文档,这似乎是一个不错的选择,另一个是使用 MongoOperations。事实上,我很惊讶为什么像这样的简单查询不起作用,它真的是一个简单的查询!一点都不复杂。我认为最好的选择是使用 Repository 进行简单查询和使用 RAW 查询的服务,如果它适用于 RAW 查询,这是必须的,否则很难使用它。但是 sprint 框架很强大,而且总是有办法的。我必须承认我根本不知道该怎么做(还)
  • 感谢您的提示,我尝试使用查询和标准,但似乎又是一个死胡同,我又浪费了几个小时,得到了问题的丑陋解决方案 UPDATE #4,它不漂亮,它更像是一个hack而不是一个解决方案,它只解决了这个特定的问题,很难,但如果我们必须使用那种类型的查询,就不能解决spring data mongo查询问题的根源,似乎最好转向其他类型的数据库或其他解决方案,在一大块 DRY 中破解一个简单的查询是一场噩梦......
  • 这似乎是一百万美元的答案......没有人知道吗?
【解决方案2】:

对我来说,它可以使“和”明确,如下所示:

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

【讨论】:

  • 感谢 Christopher Bohlen,我今天才看到这个答案,经过一番斗争,我解决了这个问题。这与您的答案非常相似。再次非常感谢你:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 2016-11-15
  • 2016-12-01
相关资源
最近更新 更多