这是我的文档:
{
"_id":"5b1ff7c53e3ac841302cfbc2",
"idProf":"5b1ff7c53e3ac841302cfbbf",
"pacientes":["5b20d2c83e3ac841302cfbdb","5b20d25f3e3ac841302cfbd0"]
}
我想知道如何使用Java中的MongoCollection
在数组中找到重复的条目。
这是我正在尝试的:
BasicDBObject query = new BasicDBObject("idProf", idProf);
query.append("$in", new BasicDBObject().append("pacientes", idJugador.toString()));
collection.find(query)
答案 0 :(得分:0)
最好的方法实际上是将数组的长度与将删除所有重复项的数组的长度进行比较。一个“集合”没有重复的条目,因此您需要做的是将一个数组转换为一个“集合”,并对照原始数组进行测试。
$expr
现代MongoDB版本具有$expr
,可在常规查询中将其与聚合表达式一起使用。在这里,我们将使用$setDifference
和$size
以及$ne
进行布尔比较的表达式。
Document query = new Document(
"$expr", new Document(
"$ne", Arrays.asList(
new Document("$size", "$pacientes"),
new Document("$size",
new Document("$setDifference", Arrays.asList("$pacientes", Collections.emptyList()))
)
)
)
);
MongoCursor<Document> cursor = collection.find(query).iterator();
序列化为:
{
"$expr": {
"$ne": [
{ "$size": "$pacientes" },
{ "$size": { "$setDifference": [ "$pacientes", [] ] } }
]
}
}
实际上,$setDifference
在进行比较并仅返回唯一元素。 $size
返回原始文档数组内容和新缩小的“集合”的长度。当然,如果这些条件“不相等”($ne
),条件将是true
,这意味着在文档中找到了重复项。
$expr
的操作是接收布尔值true/false
,以便确定文档是否符合条件。
$where
子句基本上$where
是在服务器上求值的JavaScript表达式
String whereClause = "this.pacientes.length != Object.keys(this.pacientes.reduce((o,e) => Object.assign(o, { [e.valueOf()]: null}), {})).length";
Document query = new Document("$where": whereClause);
MongoCursor<Document> cursor = collection.find(query).iterator();
您确实不需要在服务器上显式禁用JavaScript评估(这是默认设置),并且效率不如使用$expr
和本机聚合运算符。但是,可以使用$where
以相同的方式评估JavaScript表达式,并且Java代码中的参数基本上以字符串形式发送。
在表达式中.length
是所有JavaScript数组的属性,因此您具有原始文档内容以及与“集合”的比较。 Array.reduce()
将每个数组元素用作结果对象中的“键”,然后Object.keys()
将把这些“键”作为新数组返回。
由于JavaScript对象的工作方式类似于Map
,因此只允许使用唯一键,这是获得“设置”结果的一种方法。当然,当删除重复条目导致长度更改时,相同的!=
比较将返回true。
在$expr
或$where
的任何情况下,这些都是计算条件,它们不能使用集合中存在的索引。因此,通常建议在这些表达式的旁边使用其他准则,这些准则使用基于正则等式或基于范围的query expressions,这些准则的确可以利用索引。谓词中的此类附加条件将在有索引的地方极大地提高查询性能。
答案 1 :(得分:0)
我们可以尝试在您的Java应用程序代码中解决此问题。
private final MongoCollection collection;
public boolean hasDuplicatePacientes(String idProf) {
Document d = collection.find(eq("idProf", idProf)).first();
List<String> pacientes = (List<String>) d.get("pacientes");
int original = pacientes.size();
if (original == 0) {
return false;
}
Set<String> unique = new HashSet(pacientes);
return original != unique.size();
}
或者,如果您正在寻找一种在数据库端完全实现此目的的方法,那么我相信使用提供的Neil Lunn之类的方法也是可行的。