sql >> Database >  >> NoSQL >> MongoDB

Hoe $regex te gebruiken binnen $of als een aggregatie-expressie

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.




  1. Hoe configureer ik mijn MongoDB om rekening te houden met UTF-8?

  2. Resultaten filteren op de laatste array-invoerveldwaarde

  3. Hoe werkt redis om te helpen bij persistentie van de sessie in azure?

  4. MongoDB neemt mlab over - Wat zijn de verschillende MongoDB-hostingalternatieven?