我想使用 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
对象,但这并不能解决问题。
您可以创建这样的方法:
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