从 MongoDB 中选择符合 K 个标准的数据
Selecting data from MongoDB where K of N criterias are met
我有包含四个字段的文档:A、B、C、D 现在我需要查找至少三个字段匹配的文档。例如:
查询:A=a,B=b,C=c,D=d
返回的文件:
- a,b,c,d (four of four met)
- a,b,c (three of four met)
- a,b,d (another three of four met)
- a,c,d (another three of four met)
- b,c,d (another three of four met)
到目前为止,我创建了如下内容:
`(A=a AND B=b AND C=c)
OR (A=a AND B=b AND D=d)
OR (A=a AND C=c AND D=d)
OR (B=b AND C=c AND D=d)`
但这很丑陋且容易出错。
有没有更好的实现方式?此外,查询性能很重要。
我正在使用 Spring 数据,但我认为这无关紧要。我当前的代码:
Criteria c = new Criteria();
Criteria ca = Criteria.where("A").is(doc.getA());
Criteria cb = Criteria.where("B").is(doc.getB());
Criteria cc = Criteria.where("C").is(doc.getC());
Criteria cd = Criteria.where("D").is(doc.getD());
c.orOperator(
new Criteria().andOperator(ca,cb,cc),
new Criteria().andOperator(ca,cb,cd),
new Criteria().andOperator(ca,cc,cd),
new Criteria().andOperator(cb,cc,cd)
);
Query query = new Query(c);
return operations.find(query, Document.class, "documents");
目前在 MongoDB 中我们无法直接执行此操作,因为我们没有任何功能支持 Permutation/Combination 查询参数。
但我们可以通过将条件分解成多个部分来简化查询。
使用Aggregation管道
$project with records (A=a AND B=b) --> This will give the records which are having two conditions matching.
(我们的 objective 是在给定条件下查找匹配 4 中的 3 或 4 中的 4 的记录)`
Next in the pipeline use OR condition (C=c OR D=d) to find the final set of records which yields our expected result.
希望对您有所帮助!
按照您的方式,您必须在查询中进行所有排列。您可以使用聚合框架来执行此操作而无需排列所有组合。而且它足够通用,可以处理任何 K
。缺点是我认为你需要 Mongodb 3.2+ 并且 Spring 数据还不支持这些操作:$filter $concatArrays
但是您可以使用 java 驱动程序轻松完成。
[
{
$project:{
totalMatched:{
$size:{
$filter:{
input:{
$concatArrays:[ ["$A"], ["$B"], ["$C"],["$D"]]
},
as:"attr",
cond:{
$eq:["$$attr","a"]
}
}
}
}
}
},
{
$match:{
totalMatched:{ $gte:3 }
}
}
]
您所做的只是将需要检查的所有字段的值连接到一个数组中。然后 select 这些元素的子集等于您要查找的值(或您想要的任何条件),最后获得每个文档的数组大小。
现在您需要做的就是$match大小大于或等于您想要的文档。
我有包含四个字段的文档:A、B、C、D 现在我需要查找至少三个字段匹配的文档。例如:
查询:A=a,B=b,C=c,D=d
返回的文件:
- a,b,c,d (four of four met)
- a,b,c (three of four met)
- a,b,d (another three of four met)
- a,c,d (another three of four met)
- b,c,d (another three of four met)
到目前为止,我创建了如下内容:
`(A=a AND B=b AND C=c)
OR (A=a AND B=b AND D=d)
OR (A=a AND C=c AND D=d)
OR (B=b AND C=c AND D=d)`
但这很丑陋且容易出错。
有没有更好的实现方式?此外,查询性能很重要。
我正在使用 Spring 数据,但我认为这无关紧要。我当前的代码:
Criteria c = new Criteria();
Criteria ca = Criteria.where("A").is(doc.getA());
Criteria cb = Criteria.where("B").is(doc.getB());
Criteria cc = Criteria.where("C").is(doc.getC());
Criteria cd = Criteria.where("D").is(doc.getD());
c.orOperator(
new Criteria().andOperator(ca,cb,cc),
new Criteria().andOperator(ca,cb,cd),
new Criteria().andOperator(ca,cc,cd),
new Criteria().andOperator(cb,cc,cd)
);
Query query = new Query(c);
return operations.find(query, Document.class, "documents");
目前在 MongoDB 中我们无法直接执行此操作,因为我们没有任何功能支持 Permutation/Combination 查询参数。
但我们可以通过将条件分解成多个部分来简化查询。
使用Aggregation管道
$project with records (A=a AND B=b) --> This will give the records which are having two conditions matching.
(我们的 objective 是在给定条件下查找匹配 4 中的 3 或 4 中的 4 的记录)`
Next in the pipeline use OR condition (C=c OR D=d) to find the final set of records which yields our expected result.
希望对您有所帮助!
按照您的方式,您必须在查询中进行所有排列。您可以使用聚合框架来执行此操作而无需排列所有组合。而且它足够通用,可以处理任何 K
。缺点是我认为你需要 Mongodb 3.2+ 并且 Spring 数据还不支持这些操作:$filter $concatArrays
但是您可以使用 java 驱动程序轻松完成。
[
{
$project:{
totalMatched:{
$size:{
$filter:{
input:{
$concatArrays:[ ["$A"], ["$B"], ["$C"],["$D"]]
},
as:"attr",
cond:{
$eq:["$$attr","a"]
}
}
}
}
}
},
{
$match:{
totalMatched:{ $gte:3 }
}
}
]
您所做的只是将需要检查的所有字段的值连接到一个数组中。然后 select 这些元素的子集等于您要查找的值(或您想要的任何条件),最后获得每个文档的数组大小。
现在您需要做的就是$match大小大于或等于您想要的文档。