【问题标题】:How to check that value equals at least one field from list?如何检查该值是否等于列表中的至少一个字段?
【发布时间】:2017-12-20 12:36:52
【问题描述】:

我有这样的方法:

for (String fieldName : fieldArray) {
        Query query = new Query();
        query.addCriteria(Criteria.where("data." + fieldName).is("some_constant"));
        if (mongoTemplate.find(query, DataPoint.class).size() > 0) {
            return true;
      }
}
return false;

这段代码看起来效率很低,因为它访问db的fieldArray大小是多少。

有没有办法使用单个查询来替换它?

【问题讨论】:

  • 您想要OR 请求? where crit1 OR crit2 OR crit3

标签: java spring mongodb spring-data


【解决方案1】:

为什么不使用 Criteria::in 方法并传递一个 List 而不是迭代所有元素并逐个检查元素,我认为您只需要这个:

query.addCriteria(
  Criteria.where("data." + fieldName).in(fieldArray)
);

除了@Veeram 的评论之外,如果您想检查一个字段是否可以保存列表中的一个值,第一种方法将起作用,但您的问题似乎不同,据我所知,您想检查一个在多个字段中退出值,您可以使用来解决此问题:

//Consider you want to check in multiple fields
List<String> fieldArray = Arrays.asList("field1", "field2", "field3");

// First you have to create a list of Criteria (multiple conditions)
List<Criteria> listOfCondition = new ArrayList<>();
for (String fieldName : fieldArray) {
    listOfCondition.add(
            Criteria.where("data." + fieldName).is("some_constant")
    );
}

//The add them to the query.
Criteria criteria = new Criteria();
for (Criteria c : listOfCondition) {
    criteria = criteria.orOperator(c);
}
Query query = new Query();
query.addCriteria(criteria);
//Then execute your query just one time

您可以使用流:

List<String> fieldArray = Arrays.asList("field1", "field2", "field3");
Criteria principaleCriteria = new Criteria();
fieldArray.stream()
        .map(fieldName -> Criteria.where("data." + fieldName).is("some_constant"))
        .forEach(criteria -> principaleCriteria.orOperator(criteria));
Query query = new Query();
query.addCriteria(principaleCriteria);
return mongoTemplate.count(query, DataPoint.class) > 0;

虽然在技术上是正确的,但当你运行代码时你会得到

org.springframework.data.mongodb.InvalidMongoDbApiUsageException:到期 由于 com.mongodb.BasicDBObject 的限制,您不能添加 第二个 '$or' 表达式指定为 '$or : [ { "data.field2" : “一些常数”}]'。条件已经包含 '$or : [ { "data.field1" : "some_constant"}]'。

Mongodb 兼容代码:

List<String> fieldArray = Arrays.asList("field1", "field2", "field3");
Criteria principaleCriteria = new Criteria();
List<Criteria> orExpressions = fieldArray.stream()
                .map(fieldName -> Criteria.where("data." + fieldName).is("some_constant"))
                .collect(toList());
Query query = new Query();
        query.addCriteria(principaleCriteria.orOperator(orExpressions.toArray(new Criteria[orExpressions.size()])));

输出:

{ "$or" : [ { "data.field1" : "some_constant"} , { "data.field2" : "some_constant"} , { "data.field3" : "some_constant"}]}

【讨论】:

  • In 运算符将不起作用,因为 Op 正在查询常量的键列表。
  • 哎呀这是正确的@Veeram 我认为 OP 检查字段名称不正确,让我深呼吸并仔细阅读。
  • 检查我的答案@Veeram 我认为这可以帮助操作
  • 你快到了。你只需要$or 条件一起。
  • 我想出了一个类似的解决方案,而您的解决方案已被删除...请注意 orOperator 接受可变参数。
【解决方案2】:

在我看来你可以使用public Criteria orOperator(Criteria... criteria)

应该是这样的:

List<Criteria> criterias = new ArrayList<>();
for (String fieldName : fieldArray) {
    //Create the criterias like you want
    criterias.add(Criteria.where("data." + fieldName).is("some_constant"));
}

Query query = new Query(
    new Criteria().orOperator(
        criterias.toArray( //convert the list into an Criteria[] for the varargs parameter
            new Criteria[criterias.size()]
        )
    )
);

这将创建一个 Criteria 列表,用于生成一个 Criteria 实例,如果一个条件有效(OR 操作,一个 true 就足够了),该实例将有效。

【讨论】:

  • 看起来像牙 - 我会检查
猜你喜欢
  • 2012-08-18
  • 2013-04-13
  • 2020-05-11
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 2021-12-03
  • 2021-10-21
  • 1970-01-01
相关资源
最近更新 更多