使用 QueryDSL 和 Spring Data 创建 $elemMatch mongo 查询

问题描述 投票:0回答:1

我想使用 QueryDSL 创建一个查询来替换它:

@Query(value = "{mappings: {$elemMatch: {'key': ?0, 'value': {$in: ?1}}}}")
List<MyObject> findByMapping(String key, Set<String> values);

MyObject
是:

class MyObject {
  Set<Mapping> mappings;
}

Mapping
是:

class Mapping {
  String key;
  String value;
}

我尝试使用

.and()
创建查询,但最终会带来映射中具有给定键的所有文档以及任何键值对中的值,而不仅仅是那些具有匹配键的文档。

例如:

{
  _id: 1,
  mappings: [{
    key: 'a', value: 1
  }, {
    key: 'b', value: 3
  }, {
    key: 'a', value: 2
  }]
},
{
  _id: 2,
  mappings: [{
    key: 'a', value: 3
  }, {
    key: 'b', value: 2
  }, {
    key: 'b', value: 1
  }]
}

如果我用

findByMapping("a", hashSet);
调用
hashSet.add(1) and hashSet.add(2)
,我希望它只检索第一个文档,因为它是唯一具有
a->1
a->2
键值对的文档,但它最终会检索这两个文档,因为它看到它们两者都有带有“a”键的映射,并且都有带有值 1 和 2 的映射。

我知道我可以轻松地用简单的 HashMap 替换

Mapping
对象,但这并不能解决问题。

mongodb spring-data querydsl
1个回答
1
投票

您可以创建这样的方法:

public static <D, Q extends SimpleExpression<D>> PredicateOperation elemMatch(@NonNull ListPath<D, Q> path,
                                                                              @NonNull Q queryDocument,
                                                                              @NonNull List<Function<Q, Predicate>> predicates) {
return ExpressionUtils.predicate(
    MongodbOps.ELEM_MATCH,
    path.any(),
    ExpressionUtils.allOf(predicates
        .stream()
        .map(predicate -> predicate.apply(queryDocument)).toList())
    );
}

然后您可以通过以下方式使用它:

personRepository.findAll(
    QPerson.person.name.eq("Luke")
            .and(elemMatch(
                QPerson.person.shippingAddresses,
                QAddress.address,
                List.of(
                    address -> address.planet.eq("Tatooine"),
                    address -> address.planet.region.eq("Outer Rim")
                )
            )));

另请参阅https://github.com/spring-projects/spring-data-mongodb/issues/1524

© www.soinside.com 2019 - 2024. All rights reserved.