如何检查该值是否等于列表中的至少一个字段?

时间:2017-12-20 12:36:53

标签: java spring mongodb spring-data

我有这样的方法:

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的访问权限如此多。

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

2 个答案:

答案 0 :(得分:4)

为什么不使用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,你不能添加一个   第二个$或者&#39;表达式指定为&#39; $或:[{&#34; data.field2&#34; :   &#34; some_constant&#34;}]&#39 ;.标准已包含&#39; $或:[{&#34; data.field1&#34;   :&#34; some_constant&#34;}]&#39;。

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

答案 1 :(得分:3)

我觉得你可以使用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就足够了),该实例将有效。