Allt inuti $expr
är ett aggregeringsuttryck och dokumentationen får inte "säga att du inte uttryckligen kan" , men avsaknaden av någon namngiven operatör
och JIRA issue SERVER-11947
säkert säga det. Så om du behöver ett reguljärt uttryck har du verkligen inget annat alternativ än att använda $where
istället:
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";
}
})
Du kan fortfarande använda $expr
och aggregeringsuttryck för en exakt matchning, eller bara håll jämförelsen inom $where
i alla fall. Men för närvarande är de enda reguljära uttryck som MongoDB förstår $regex
inom ett "query"-uttryck
.
Om du faktiskt "krävde" ett aggregeringspipelineuttryck som hindrar dig från att använda $where
, då är den enda giltiga metoden att först "projicera" fältet separat från arrayen och sedan $match
med det vanliga frågeuttrycket:
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/]
}
}}
])
Vilket leder oss till det faktum att du verkar leta efter objektet i arrayen med det maximala datumvärdet. JavaScript-syntaxen borde göra det tydligt att det korrekta tillvägagångssättet här istället är att $sort
arrayen på "uppdatering". På så sätt kan det "första" objektet i arrayen vara det "senaste". Och det här är något du kan göra med en vanlig fråga.
För att behålla ordningen, se till att nya objekt läggs till i arrayen med $push
och $sort
så här:
db.getCollection('permits').updateOne(
{ "_id": _idOfDocument },
{
"$push": {
"inspections": {
"$each": [{ /* Detail of inspection object */ }],
"$sort": { "inspectionDate": -1 }
}
}
}
)
Faktiskt med ett tomt array-argument till $each
en updateMany()
kommer att uppdatera alla dina befintliga dokument:
db.getCollection('permits').updateMany(
{ },
{
"$push": {
"inspections": {
"$each": [],
"$sort": { "inspectionDate": -1 }
}
}
}
)
Dessa borde egentligen bara vara nödvändiga när du faktiskt "ändrar" datumet som lagras under uppdateringar, och dessa uppdateringar ges bäst med bulkWrite()
för att effektivt göra "både" uppdateringen och "sorten" av arrayen:
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 } } }
}
}}
])
Men om du aldrig faktiskt "ändrade" datumet, är det förmodligen mer meningsfullt att helt enkelt använda $position
modifierare och "pre-pend" till arrayen istället för att "lägga till" och undvika all overhead av en $sort
:
db.getCollection('permits').updateOne(
{ "_id": _idOfDocument },
{
"$push": {
"inspections": {
"$each": [{ /* Detail of inspection object */ }],
"$position": 0
}
}
}
)
Med arrayen permanent sorterad eller åtminstone konstruerad så att det "senaste" datumet faktiskt alltid är den "första" posten, då kan du helt enkelt använda ett vanligt frågeuttryck:
db.getCollection('permits').find({
"inspections.0.description": {
"$in": [/^Found a .* at the property$/,/Health Inspection/]
}
})
Så lektionen här är att inte försöka tvinga fram beräknade uttryck på din logik där du verkligen inte behöver. Det bör inte finnas någon övertygande anledning till varför du inte kan beställa arrayinnehållet som "lagrat" för att ha det "senaste datumet första " , och även om du trodde att du behövde arrayen i någon annan ordning bör du förmodligen väga upp vilket användningsfall som är viktigast.
När du har omoderat kan du till och med dra nytta av ett index i viss utsträckning så länge som de reguljära uttrycken antingen är förankrade i början av strängen eller åtminstone något annat i frågeuttrycket matchar exakt.
Om du känner att du verkligen inte kan ordna om arrayen, då $var
fråga är ditt enda nuvarande alternativ tills JIRA-problemet löser sig. Vilket förhoppningsvis faktiskt är för 4.1-utgåvan som för närvarande målet, men det är mer än troligt 6 månader till ett år vid bästa uppskattning.