Alles binnen $expr
is een aggregatie-expressie, en de documentatie mag niet "zeggen dat je niet expliciet kunt" , maar het gebrek aan een benoemde operator
en het JIRA-probleem SERVER-11947
zeg dat zeker. Dus als je een reguliere expressie nodig hebt, dan heb je echt geen andere optie dan $where
in plaats daarvan:
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";
}
})
U kunt nog steeds gebruik maken van $expr
en aggregatie-expressies voor een exacte overeenkomst, of houd de vergelijking binnen de $where
hoe dan ook. Maar op dit moment is de enige reguliere expressie die MongoDB begrijpt, $regex
binnen een "query"-expressie
.
Als u daadwerkelijk "vereist" een aggregatiepijplijnexpressie die u uitsluit $where
, dan is de enige huidige geldige benadering om eerst het veld afzonderlijk van de array te "projecteren" en vervolgens $match
met de reguliere zoekexpressie:
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/]
}
}}
])
Dat brengt ons bij het feit dat u lijkt te zoeken naar het item in de array met de maximale datumwaarde. De JavaScript-syntaxis zou duidelijk moeten maken dat de juiste benadering hier is om $sort
de array op "update". Op die manier kan het "eerste" item in de array het "laatste" zijn. En dit is iets wat je kunt doen met een gewone zoekopdracht.
Om de volgorde te behouden, moet u ervoor zorgen dat nieuwe items aan de array worden toegevoegd met $push
en $sort
zoals dit:
db.getCollection('permits').updateOne(
{ "_id": _idOfDocument },
{
"$push": {
"inspections": {
"$each": [{ /* Detail of inspection object */ }],
"$sort": { "inspectionDate": -1 }
}
}
}
)
In feite met een leeg array-argument naar $each
een updateMany()
zal al uw bestaande documenten bijwerken:
db.getCollection('permits').updateMany(
{ },
{
"$push": {
"inspections": {
"$each": [],
"$sort": { "inspectionDate": -1 }
}
}
}
)
Deze zouden eigenlijk alleen nodig moeten zijn als u de datum die tijdens updates is opgeslagen in feite "verandert", en die updates kunnen het beste worden uitgegeven met bulkWrite()
om effectief "zowel" de update als de "sortering" van de array uit te voeren:
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 } } }
}
}}
])
Als u de datum echter nooit daadwerkelijk hebt "veranderd", is het waarschijnlijk logischer om gewoon de $position
modifier en "pre-pend" aan de array in plaats van "appending", en het vermijden van overhead van een $sort
:
db.getCollection('permits').updateOne(
{ "_id": _idOfDocument },
{
"$push": {
"inspections": {
"$each": [{ /* Detail of inspection object */ }],
"$position": 0
}
}
}
)
Met de array permanent gesorteerd of op zijn minst zo geconstrueerd dat de "laatste" datum eigenlijk altijd de "eerste" invoer is, kunt u eenvoudig een reguliere query-expressie gebruiken:
db.getCollection('permits').find({
"inspections.0.description": {
"$in": [/^Found a .* at the property$/,/Health Inspection/]
}
})
Dus de les hier is:probeer geen berekende uitdrukkingen op je logica te forceren waar dat echt niet nodig is. Er mag geen dwingende reden zijn waarom u de array-inhoud niet kunt bestellen als "opgeslagen" om de "laatste datum eerst te hebben " , en zelfs als u dacht dat u de array in een andere volgorde nodig had, moet u waarschijnlijk afwegen welke gebruikssituatie belangrijker is.
Eenmaal opnieuw gecodeerd, kunt u zelfs tot op zekere hoogte profiteren van een index, zolang de reguliere expressies ofwel verankerd zijn aan het begin van de tekenreeks of tenminste iets anders in de query-expressie een exacte overeenkomst heeft.
Als je denkt dat je de array echt niet opnieuw kunt ordenen, gebruik dan de $where
query is uw enige huidige optie totdat het JIRA-probleem is opgelost. Dat is hopelijk eigenlijk voor de 4.1-release zoals momenteel getarget, maar dat is meer dan waarschijnlijk 6 maanden tot een jaar bij de beste schatting.