MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Как да използвате $regex в $or като агрегиращ израз

Всичко вътре $expr е израз за агрегиране и документацията може да не "казва, че не можете изрично" , но липса на който и да е наименуван оператор и проблемът на JIRA SERVER-11947 със сигурност го кажи. Така че, ако имате нужда от регулярен израз, тогава наистина нямате друга опция освен да използвате $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 и изрази за агрегиране за точно съвпадение или просто запазете сравнението в $където така или иначе. Но в момента единствените регулярни изрази, които MongoDB разбира, са $regex в рамките на израз "query" .

Ако наистина сте „изисквали“ израз на тръбопровода за агрегиране, който ви пречи да използвате $where , тогава единственият настоящ валиден подход е първо да се „проектира“ полето отделно от масива и след това $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 масива на "актуализация". По този начин "първият" елемент в масива може да бъде "последният". И това е нещо, което можете да направите с обикновена заявка.

За да поддържате реда, уверете се, че нови елементи са добавени към масива с $push и $sort като това:

db.getCollection('permits').updateOne(
  { "_id": _idOfDocument },
  {
    "$push": {
      "inspections": {
        "$each": [{ /* Detail of inspection object */ }],
        "$sort": { "inspectionDate": -1 }
      }
    }
  }
)

Всъщност с празен аргумент за масив към $each updateMany() ще актуализира всички ваши съществуващи документи:

db.getCollection('permits').updateMany(
  { },
  {
    "$push": {
      "inspections": {
        "$each": [],
        "$sort": { "inspectionDate": -1 }
      }
    }
  }
)

Те наистина трябва да са необходими само когато всъщност „промените“ датата, съхранена по време на актуализации, и тези актуализации се издават най-добре с 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 модификатор и „предварително добавяне“ към масива вместо „добавяне“ и избягване на всякакви допълнителни разходи на $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/]
  }
})

Така че урокът тук е да не се опитвате да наложите изчислени изрази върху логиката си, когато наистина не е необходимо. Не трябва да има убедителна причина, поради която не можете да наредите съдържанието на масива като "съхранено", за да има "най-нова дата първа " и дори ако смятате, че имате нужда от масива в друг ред, тогава вероятно трябва да прецените кой случай на използване е по-важен.

Веднъж пренаредени, можете дори да се възползвате от индекс до известна степен, стига регулярните изрази да са или закотвени към началото на низа, или поне нещо друго в израза на заявката има точно съвпадение.

В случай, че смятате, че наистина не можете да пренаредите масива, тогава $където query е единствената ви настояща опция, докато проблемът с JIRA не бъде разрешен. Което се надяваме всъщност да е за изданието 4.1, както е предвидено в момента, но това е повече от вероятно 6 месеца до една година при най-добра оценка.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Вземете данни от mongoDB и Nodejs:toArray не е функционална грешка

  2. res.redirect показва стара информация след изпращане на формуляр?

  3. Къде е инсталиран mongoimport на Mac OS X

  4. Как да получите адреса на сървъра на сървъра, от който се изтеглят данните

  5. Преименуването на поле във вграден документ в масив в MongoDB не работи