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

Zwróć dokument z dokumentem podrzędnym Max

Po pierwsze, pokażmy Twoje dane w sposób, w jaki ludzie mogą je wykorzystać i uzyskać pożądany rezultat:

{ value: 1,
  _id: ObjectId('5cb9ea0c75c61525e0176f96'),
  name: 'Test',
  category: 'Development',
  subcategory: 'Programming Languages',
  status: 'Supported',
  description: 'Test',
  change:
   [ { version: 1,
       who: 'ATL User',
       when: new Date('2019-04-19T15:30:39.912Z'),
       what: 'Item Creation' },
     { version: 2,
       who: 'ATL Other User',
       when: new Date('2019-04-19T15:31:39.912Z'),
       what: 'Name Change' } ],
}

Zauważ, że "kiedy" daty są w rzeczywistości różne, więc będzie $max wartość i nie są po prostu takie same. Teraz możemy przejrzeć sprawy

Przypadek 1 – Pobierz „liczbę pojedynczą” $max wartość

Podstawowym przypadkiem jest użycie $arrayElemAt i $indexOfArray operatorów, aby zwrócić pasujące $max wartość:

db.items.aggregate([
  { "$match": {
    "subcategory": "Programming Languages", "name": { "$exists": true }
  }}, 
  { "$addFields": {
    "change": {
      "$arrayElemAt": [
        "$change",
        { "$indexOfArray": [
          "$change.when",
          { "$max": "$change.when" }
        ]}
      ]
    }
  }}
])

Zwroty:

{
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : {
                "version" : 2,
                "who" : "ATL Other User",
                "when" : ISODate("2019-04-19T15:31:39.912Z"),
                "what" : "Name Change"
        }
}

Zasadniczo "$max":"$change.when" zwraca wartość, która jest „maksimum” z tej tablicy wartości. Następnie znajdziesz pasujący „indeks” tej tablicy wartości za pomocą $indexOfArray który zwraca pierwszy znaleziono pasujący indeks. Ta pozycja "indeks" (w rzeczywistości tylko z tablicy "kiedy" wartości transponowane w tej samej kolejności ) są następnie używane z $arrayElemAt aby wyodrębnić „cały obiekt” z „zmiany” tablica w określonej pozycji indeksu.

Przypadek 2 – Zwróć „wiele” $max wpisy

Prawie to samo z $max , ale tym razem $filter aby zwrócić wiele "możliwych" wartości pasujące do $max wartość:

db.items.aggregate([
  { "$match": {
    "subcategory": "Programming Languages", "name": { "$exists": true }
  }}, 
  { "$addFields": {
    "change": {
      "$filter": {
        "input": "$change",
        "cond": {
          "$eq": [ "$$this.when", { "$max": "$change.when" } ]
        }
      }       
    }
  }}
])

Zwroty:

{
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : [
                {
                        "version" : 2,
                        "who" : "ATL Other User",
                        "when" : ISODate("2019-04-19T15:31:39.912Z"),
                        "what" : "Name Change"
                }
        ]
}

Tak więc $max jest oczywiście taka sama, ale tym razem pojedyncza wartość zwracana przez ten operator jest używana w $eq porównanie w ramach $filter . Sprawdza każdy element tablicy i sprawdza bieżący "kiedy" wartość ( "$$this.kiedy" ). Gdzie "równe" wtedy element jest zwracany.

Zasadniczo to samo co pierwsze podejście, ale z tą różnicą, że $filter umożliwia „wiele” elementy do zwrócenia. Dlatego wszystko z tym samym $max wartość.

Przypadek 3 – Wstępne sortowanie zawartości tablicy.

Teraz możesz zauważyć, że w przykładowych danych, które zawarłem (zaadaptowane z twoich własnych, ale z rzeczywistą datą „max”), wartość „max” jest w rzeczywistości ostatnią wartość w tablicy. Może się to po prostu naturalnie zdarzyć, ponieważ $push ( domyślnie ) "dołącza" do końca istniejącej zawartości tablicy. A więc „nowsze” wpisy będą zwykle znajdować się na końcu tablicy.

Jest to oczywiście domyślne zachowanie, ale istnieją dobre powody, dla których „możesz” chcę to zmienić. W skrócie najlepsze sposób na uzyskanie „najnowszych” wpis tablicy ma w rzeczywistości zwrócić pierwszy element z tablicy.

Wszystko, co musisz zrobić, to upewnić się, że "najnowsze" jest faktycznie dodany pierwszy zamiast ostatni . Istnieją dwa podejścia:

  1. Użyj $position aby „założyć” elementy tablicy: Jest to prosty modyfikator $push używając 0 pozycja aby zawsze dodawać do przódu :

    db.items.updateOne(
      { "_id" : ObjectId("5cb9ea0c75c61525e0176f96") },
      { "$push": {
          "change": {
            "$each": [{
              "version": 3,
              "who": "ATL User",
              "when": new Date(),
              "what": "Another change"
            }],
            "$position": 0
          }
       }}
    )
    

    Zmieniłoby to dokument na:

    {
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : [
                {
                        "version" : 3,
                        "who" : "ATL User",
                        "when" : ISODate("2019-04-20T02:40:30.024Z"),
                        "what" : "Another change"
                },
                {
                        "version" : 1,
                        "who" : "ATL User",
                        "when" : ISODate("2019-04-19T15:30:39.912Z"),
                        "what" : "Item Creation"
                },
                {
                        "version" : 2,
                        "who" : "ATL Other User",
                        "when" : ISODate("2019-04-19T15:31:39.912Z"),
                        "what" : "Name Change"
                }
        ]
    }
    

Zauważ, że wymagałoby to wcześniejszego „odwrócenia” wszystkich elementów tablicy, tak aby „najnowszy” był już na początku, aby zachować kolejność. Na szczęście jest to nieco omówione w drugim podejściu...

  1. Użyj $sort modyfikować dokumenty w kolejności na każdym $push : I to jest inny modyfikator, który faktycznie „przesortowuje” atomowo przy każdym dodaniu nowego przedmiotu. Normalne użycie jest w zasadzie takie samo z każdym nowym elementem $each jak powyżej, lub nawet po prostu „pustą” tablicę w celu zastosowania $sortuj tylko do istniejących danych:

    db.items.updateOne(
      { "_id" : ObjectId("5cb9ea0c75c61525e0176f96") },
      { "$push": {
          "change": {
            "$each": [],
            "$sort": { "when": -1 } 
          }
       }}
    )
    

    Wyniki w:

    {
            "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
            "value" : 1,
            "name" : "Test",
            "category" : "Development",
            "subcategory" : "Programming Languages",
            "status" : "Supported",
            "description" : "Test",
            "change" : [
                    {
                            "version" : 3,
                            "who" : "ATL User",
                            "when" : ISODate("2019-04-20T02:40:30.024Z"),
                            "what" : "Another change"
                    },
                    {
                            "version" : 2,
                            "who" : "ATL Other User",
                            "when" : ISODate("2019-04-19T15:31:39.912Z"),
                            "what" : "Name Change"
                    },
                    {
                            "version" : 1,
                            "who" : "ATL User",
                            "when" : ISODate("2019-04-19T15:30:39.912Z"),
                            "what" : "Item Creation"
                    }
            ]
    }
    

    Może minąć minuta, aby zrozumieć, dlaczego $push w celu $sort tablica taka jak ta, ale ogólną intencją jest to, że można dokonać modyfikacji tablicy, która "zmienia" właściwość, taką jak Date sortowanej wartości i użyjesz takiego stwierdzenia, aby odzwierciedlić te zmiany. Lub po prostu dodaj nowe elementy za pomocą $sort i niech to zadziała.

Dlaczego więc „sklep” tablica uporządkowana w ten sposób? Jak wspomniano wcześniej, chcesz pierwszego jako „najnowszy” , a następnie zapytanie do zwrócenia staje się po prostu:

db.items.find(
  {
    "subcategory": "Programming Languages",
    "name": { "$exists": true }
  },
  { "change": { "$slice": 1 } }
)

Zwroty:

{
        "_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
        "value" : 1,
        "name" : "Test",
        "category" : "Development",
        "subcategory" : "Programming Languages",
        "status" : "Supported",
        "description" : "Test",
        "change" : [
                {
                        "version" : 3,
                        "who" : "ATL User",
                        "when" : ISODate("2019-04-20T02:40:30.024Z"),
                        "what" : "Another change"
                }
        ]
}

Tak więc $slice może być następnie użyty tylko do wyodrębnienia elementów tablicy według znanych indeksów. Technicznie możesz po prostu użyć -1 tam, aby zwrócić ostatni w każdym razie element tablicy, ale zmiana kolejności, w której najnowsza jest pierwsza, pozwala na inne rzeczy, takie jak potwierdzenie ostatniej modyfikacji dokonanej przez określonego użytkownika i/lub inne warunki, takie jak ograniczenie zakresu dat. czyli:

db.items.find(
  {
    "subcategory": "Programming Languages",
    "name": { "$exists": true },
    "change.0.who": "ATL User",
    "change.0.when": { "$gt": new Date("2018-04-01") }
  },
  { "change": { "$slice": 1 } }
)

Zauważając, że coś takiego jak "zmień.-1.kiedy" jest niedozwolonym stwierdzeniem, dlatego w zasadzie zmieniamy kolejność tablicy, aby można było użyć legal 0 na pierwszy zamiast -1 na ostatni .

Wniosek

Jest więc kilka różnych rzeczy, które możesz zrobić, używając podejścia agregacyjnego do filtrowania zawartości tablicy lub za pomocą standardowych formularzy zapytań po dokonaniu pewnych modyfikacji w sposobie przechowywania danych. To, którego użyć, zależy od Twoich okoliczności, ale należy zauważyć, że każdy ze standardowych formularzy zapytań będzie działać znacznie szybciej niż jakakolwiek manipulacja za pośrednictwem struktury agregacji lub dowolnych operatorów obliczeniowych.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. zmniejsz wartość w kolekcji do 0

  2. Nadpisz obiekt w mongodb

  3. mongoose vs mongodb (moduły/rozszerzenia nodejs), co jest lepsze? i dlaczego?

  4. MongoDB:sprawdź połączenie z DB

  5. MongoEngine wycinający zestaw zapytań (mongodb z django)