里面的一切$expr https://docs.mongodb.com/manual/reference/operator/query/expr/是一个聚合表达式,文档可能没有“明确地说你不能”,但是缺少任何指定的运算符 https://docs.mongodb.com/manual/reference/operator/aggregation/和JIRA 问题 SERVER-11947 https://jira.mongodb.org/browse/SERVER-11947当然这么说。因此,如果您需要正则表达式,那么除了使用之外您别无选择$where https://docs.mongodb.com/manual/reference/operator/query/where/反而:
db.getCollection('permits').find({
"$where": function() {
var description = this.inspections
.sort((a,b) => b.inspectionDate.valueOf() - a.inspectionDate.valueOf())
.shift().description;
return /^Found a .* at the property$/.test(description) ||
description === "Health Inspection";
}
})
您仍然可以使用$expr https://docs.mongodb.com/manual/reference/operator/query/expr/和聚合表达式以实现精确匹配,或者只是将比较保持在$where https://docs.mongodb.com/manual/reference/operator/query/where/反正。但此时 MongoDB 唯一理解的正则表达式是$regex https://docs.mongodb.com/manual/reference/operator/query/regex/在一个“查询”表达式 https://docs.mongodb.com/manual/reference/operator/query/.
如果你真的这么做了“要求”阻止您使用的聚合管道表达式$where https://docs.mongodb.com/manual/reference/operator/query/where/,那么当前唯一有效的方法是首先将字段与数组分开“投影”,然后$match https://docs.mongodb.com/manual/reference/operator/aggregation/match/与正则查询表达式:
db.getCollection('permits').aggregate([
{ "$addFields": {
"lastDescription": {
"$arrayElemAt": [
"$inspections.description",
{ "$indexOfArray": [
"$inspections.inspectionDate",
{ "$max": "$inspections.inspectionDate" }
]}
]
}
}},
{ "$match": {
"lastDescription": {
"$in": [/^Found a .* at the property$/,/Health Inspection/]
}
}}
])
这让我们发现您似乎正在寻找数组中具有最大日期值的项目。 JavaScript 语法应该清楚地表明这里正确的方法是$sort https://docs.mongodb.com/manual/reference/operator/update/sort/“更新”时的数组。这样,数组中的“第一个”项目可以是“最新的”。这是您可以通过常规查询完成的事情。
为了维持顺序,请确保将新项目添加到数组中$push https://docs.mongodb.com/manual/reference/operator/update/push/ and $sort https://docs.mongodb.com/manual/reference/operator/update/sort/像这样:
db.getCollection('permits').updateOne(
{ "_id": _idOfDocument },
{
"$push": {
"inspections": {
"$each": [{ /* Detail of inspection object */ }],
"$sort": { "inspectionDate": -1 }
}
}
}
)
事实上,用一个空数组参数$each https://docs.mongodb.com/manual/reference/operator/update/each/ an updateMany() https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/将更新您所有现有的文档:
db.getCollection('permits').updateMany(
{ },
{
"$push": {
"inspections": {
"$each": [],
"$sort": { "inspectionDate": -1 }
}
}
}
)
实际上,只有当您实际上“更改”更新期间存储的日期时,这些才是必要的,并且这些更新最好通过bulkWrite() https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/有效地对数组进行“更新”和“排序”:
db.getCollection('permits').bulkWrite([
{ "updateOne": {
"filter": { "_id": _idOfDocument, "inspections._id": indentifierForArrayElement },
"update": {
"$set": { "inspections.$.inspectionDate": new Date() }
}
}},
{ "updateOne": {
"filter": { "_id": _idOfDocument },
"update": {
"$push": { "inspections": { "$each": [], "$sort": { "inspectionDate": -1 } } }
}
}}
])
但是,如果您实际上从未“更改”日期,那么简单地使用$position https://docs.mongodb.com/manual/reference/operator/update/position/修饰符和“预先挂起”到数组而不是“附加”,并避免了任何开销$sort https://docs.mongodb.com/manual/reference/operator/update/sort/:
db.getCollection('permits').updateOne(
{ "_id": _idOfDocument },
{
"$push": {
"inspections": {
"$each": [{ /* Detail of inspection object */ }],
"$position": 0
}
}
}
)
通过永久排序或至少构造数组,使“最新”日期实际上始终是“第一个”条目,然后您可以简单地使用正则查询表达式:
db.getCollection('permits').find({
"inspections.0.description": {
"$in": [/^Found a .* at the property$/,/Health Inspection/]
}
})
因此,这里的教训是,不要在真正不需要的地方尝试将计算表达式强加于您的逻辑。应该没有令人信服的理由说明为什么您不能将数组内容排序为“存储”以具有“最近日期first",即使您认为需要以任何其他顺序排列数组,那么您可能应该权衡哪种使用情况更重要。
重新排序后,您甚至可以在某种程度上利用索引,只要正则表达式锚定到字符串的开头或至少查询表达式中的其他内容执行精确匹配即可。
如果您觉得确实无法对数组重新排序,那么$where https://docs.mongodb.com/manual/reference/operator/query/where/在 JIRA 问题解决之前,query 是您唯一存在的选项。这实际上是针对当前目标的 4.1 版本的,但最好估计也很可能是 6 个月到一年。