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

Warunki dopasowania i ostatnia data z tablicy

Podstawowa koncepcja polega na tym, że potrzebujesz struktury agregacji, aby zastosować warunki do „filtrowania” elementów tablicy do warunków. W zależności od dostępnej wersji można zastosować różne techniki.

We wszystkich przypadkach jest to wynik:

{
    "_id" : ObjectId("593921425ccc8150f35e7664"),
    "user1" : 1,
    "user2" : 4,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-09T10:04:50Z"),
            "body" : "hiii 1"
    }
}
{
    "_id" : ObjectId("593921425ccc8150f35e7663"),
    "user1" : 1,
    "user2" : 3,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-10T10:04:50Z"),
            "body" : "hiii 2"
    }
}
{
    "_id" : ObjectId("593921425ccc8150f35e7662"),
    "user1" : 1,
    "user2" : 2,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-08T10:04:50Z"),
            "body" : "hiii 0"
    }
}

MongoDB 3.4 i nowsze

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$replaceRoot": {
    "newRoot": {
      "$let": {
        "vars": {
          "messages": {
            "$filter": {
              "input": "$messages",
              "as": "m",
              "cond": { "$eq": [ "$$m.sender", 1 ] }
            }
          },
          "maxDate": {
            "$max": {
              "$map": {
                "input": {
                  "$filter": {
                    "input": "$messages",
                    "as": "m",
                    "cond": { "$eq": [ "$$m.sender", 1 ] }
                  }
                },
                "as": "m",
                "in": "$$m.datetime"
              }
            }
          }
        },
        "in": {
          "_id": "$_id",
          "user1": "$user1",
          "user2": "$user2",
          "messages": {
            "$arrayElemAt": [
              { "$filter": {
                "input": "$$messages",
                "as": "m",
                "cond": { "$eq": [ "$$m.datetime", "$$maxDate" ] }
              }},
              0
            ]
          }    
        }
      }
    }
  }}
])

Jest to najbardziej wydajny sposób, który wykorzystuje $replaceRoot co pozwala nam deklarować zmienne do użycia w „zastąpionej” strukturze za pomocą $let . Główną zaletą jest to, że wymaga to tylko "dwóch" etapów potoku.

Aby dopasować zawartość tablicy, użyj $filter gdzie stosujesz $eq logiczna operacja testowania wartości "nadawcy" . Tam, gdzie warunek pasuje, zwracane są tylko pasujące wpisy tablicy.

Używając tego samego $filter aby brane pod uwagę były tylko pasujące wpisy „nadawcy”, chcemy zastosować $maks nad "filtrowaną" listą do wartości w "datetime" . $max ]5 wartość to „ostatnia” data według warunków.

Potrzebujemy tej wartości, abyśmy mogli później porównać zwrócone wyniki z tablicy „filtrowanej” z tą „maxDate”. Co dzieje się w "in" blok $let gdzie dwie „zmienne” zadeklarowane wcześniej dla filtrowanej treści i „maxDate” są ponownie stosowane do $filtr aby zwrócić to, co powinno być jedyną wartością, która spełnia oba warunki, również z "najnowszą datą".

Ponieważ chcesz tylko „jeden” wynik, używamy $arrayElemAt aby użyć wartości zamiast tablicy.

MongoDB 3.2

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$project": {
    "user1": 1,
    "user2": 1,
    "messages": {
      "$filter": {
        "input": "$messages",
        "as": "m",
        "cond": { "$eq": [ "$$m.sender", 1 ] }
      }
    },
    "maxDate": {
      "$max": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$messages",
              "as": "m",
              "cond": { "$eq": [ "$$m.sender", 1 ] }
            }
          },
          "as": "m",
          "in": "$$m.datetime"
        }
      }
    }         
  }},
  { "$project": {
    "user1": 1,
    "user2": 1,
    "messages": {
      "$arrayElemAt":[
       { "$filter": {
         "input": "$messages",
          "as": "m",
          "cond": { "$eq": [ "$$m.datetime", "$maxDate" ] }
       }},
       0
      ]
    }
  }}
])

Jest to zasadniczo ten sam proces, jak opisano, ale bez $ zastąp katalog główny etap potoku, musimy złożyć wniosek w dwóch $project gradacja. Powodem tego jest to, że potrzebujemy „obliczonej wartości” z „maxDate”, aby wykonać tę ostateczną $filter , i nie jest dostępne w instrukcji złożonej, więc zamiast tego dzielimy potoki. Ma to niewielki wpływ na całkowity koszt operacji.

W MongoDB 2.6 do 3.0 możemy tutaj użyć większości techniki z wyjątkiem $arrayElemAt i albo zaakceptuj wynik „tablicy” z pojedynczym wpisem, albo wstaw $odpręż etap, aby poradzić sobie z tym, co powinno być teraz pojedynczym wpisem.

Wcześniejsze wersje MongoDB

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$unwind": "$messages" },
  { "$match": { "messages.sender": 1 } },
  { "$sort": { "_id": 1, "messages.datetime": -1 } },
  { "$group": {
    "_id": "$_id",
    "user1": { "$first": "$user1" },
    "user2": { "$first": "$user2" },
    "messages": { "$first": "$messages" }
  }}
])

Choć wydaje się to krótkie, jest to zdecydowanie najbardziej kosztowna operacja. Tutaj musisz użyć $unwind w celu zastosowania warunków do elementów tablicy. Jest to bardzo kosztowny proces, ponieważ tworzy kopię każdego dokumentu dla każdego wpisu tablicy i jest zasadniczo zastępowany przez nowoczesnych operatorów, którzy unikają tego w przypadku „filtrowania”.

Drugi $match stage tutaj odrzuca wszystkie elementy (teraz "dokumenty"), które nie pasują do warunku "nadawca". Następnie stosujemy $sort aby umieścić „najnowszą” datę na górze każdego dokumentu przy pomocy _id , stąd dwa klawisze sortowania.

Na koniec stosujemy $group aby po prostu odwołać się do oryginalnego dokumentu, używając $first jako akumulator, aby uzyskać element, który jest „na górze”.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. pobierz rekord z co najmniej jednym powiązanym obiektem

  2. ogranicz do przechowywania zduplikowanych wartości w mongodb

  3. MongoDB $pull składnia

  4. Jak wyodrębnić znacznik czasu z obiektu mongodb w postgresie?

  5. Jak $wyjrzeć, unikając wartości null w agregacie mongodb?