MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Jak używać $regex wewnątrz $lub jako wyrażenia agregacji?

Wszystko w środku $expr jest wyrażeniem agregującym, a dokumentacja nie może „powiedzieć, że nie można wprost” , ale brak dowolnego nazwanego operatora oraz problem z JIRA SERVER-11947 z pewnością to powiem. Więc jeśli potrzebujesz wyrażenia regularnego, to naprawdę nie masz innej opcji niż użycie $gdzie zamiast tego:

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";

  }
})

Nadal możesz używać $expr i wyrażenia agregacji dla dokładnego dopasowania lub po prostu zachowaj porównanie w $gdzie w każdym razie. Ale obecnie jedyne wyrażenia regularne, które MongoDB rozumie, to $regex w wyrażeniu „zapytanie” .

Jeśli rzeczywiście „wymagaj” wyrażenie potoku agregacji, które uniemożliwia korzystanie z $where , jedynym aktualnym poprawnym podejściem jest najpierw „zaprojektowanie” pola oddzielnie od tablicy, a następnie $match z regularnym wyrażeniem zapytania:

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/]
    }
  }}
])

Co prowadzi nas do tego, że wygląda na to, że szukasz elementu w tablicy z maksymalną wartością daty. Składnia JavaScript powinna jasno wskazywać, że poprawnym podejściem jest tutaj $sortuj tablica na "aktualizacji". W ten sposób „pierwszą” pozycją w tablicy może być „najnowsza”. I to jest coś, co możesz zrobić za pomocą zwykłego zapytania.

Aby zachować kolejność, upewnij się, że nowe elementy są dodawane do tablicy za pomocą $wciśnij i $sort tak:

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

W rzeczywistości z pustym argumentem tablicowym do $each updateMany() zaktualizuje wszystkie istniejące dokumenty:

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

Powinny one być konieczne tylko wtedy, gdy faktycznie „zmieniasz” datę przechowywaną podczas aktualizacji, a te aktualizacje najlepiej wydać za pomocą bulkWrite() aby skutecznie wykonać "zarówno" aktualizację, jak i "sortowanie" tablicy:

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 } } }
    }
  }}
])

Jeśli jednak nigdy nie „zmieniłeś” daty, prawdopodobnie bardziej sensowne jest użycie $pozycja modyfikator i "pre-pend" do tablicy zamiast "dodawania" i unikanie wszelkich narzutów $sort :

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

Gdy tablica jest trwale posortowana lub przynajmniej tak skonstruowana, że ​​„najnowsza” data jest w rzeczywistości zawsze „pierwszą” pozycją, możesz po prostu użyć zwykłego wyrażenia zapytania:

db.getCollection('permits').find({
  "inspections.0.description": { 
    "$in": [/^Found a .* at the property$/,/Health Inspection/]
  }
})

Tak więc lekcja tutaj jest taka, że ​​nie próbuj wymuszać wyrażeń obliczonych na swojej logice tam, gdzie tak naprawdę nie jest to konieczne. Nie powinno być żadnego przekonującego powodu, dla którego nie można uporządkować zawartości tablicy jako „przechowywanej” z „najnowszą datą pierwszą " , a nawet jeśli myślałeś, że potrzebujesz tablicy w innej kolejności, prawdopodobnie powinieneś rozważyć, który przypadek użycia jest ważniejszy.

Po przeprojektowaniu możesz nawet w pewnym stopniu skorzystać z indeksu, o ile wyrażenia regularne są zakotwiczone na początku ciągu lub przynajmniej coś innego w wyrażeniu zapytania jest zgodne.

Jeśli uważasz, że naprawdę nie możesz zmienić kolejności tablicy, $gdzie zapytanie jest jedyną obecną opcją, dopóki problem z JIRA nie zostanie rozwiązany. Miejmy nadzieję, że w rzeczywistości dotyczy to wersji 4.1, zgodnie z aktualnymi celami, ale w najlepszym razie jest to więcej niż 6 miesięcy do roku.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Agregacja $ lookup nie zwraca elementów oryginalnej kolejności tablicy

  2. mongo używając mongoose w węźle chcesz użyć lub i w zapytaniu

  3. MongoDB Nie można znaleźć wpisu, określając ts.t (ts jest typem sygnatury czasowej)

  4. Zaktualizuj pole o wartość innego pola w dokumencie

  5. Modelowanie blogów i ocen w mongodb i nodejs