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

Jak scalić pole tablicy w dokumencie w agregacji Mongo

TLDR;

Nowoczesne wersje powinny używać $reduce z $setUnion po początkowej $group jak pokazano:

db.collection.aggregate([
  { "$group": {
    "_id": { "Host": "$Host", "ArtId": "$ArtId" },
    "count": { "$sum": 1 },
    "tags": { "$addToSet": "$tags" }
  }},
  { "$addFields": {
    "tags": {
      "$reduce": {
        "input": "$tags",
        "initialValue": [],
        "in": { "$setUnion": [ "$$value", "$$this" ] }
      }
    }
  }}
])

Miałeś rację, znajdując $addToSet operatora, ale podczas pracy z treścią w tablicy zazwyczaj musisz przetwarzać za pomocą $unwind pierwszy. To "denormalizuje" wpisy tablicy i zasadniczo tworzy "kopię" dokumentu nadrzędnego z każdym wpisem tablicy jako pojedynczą wartością w polu. Właśnie tego potrzebujesz, aby uniknąć zachowań, które widzisz, bez użycia tego.

Twoje „liczenie” stanowi jednak interesujący problem, ale łatwo go rozwiązać za pomocą „podwójnego odwijania” po początkowym $group operacja:

db.collection.aggregate([
    // Group on the compound key and get the occurrences first
    { "$group": {
        "_id": { "Host": "$Host", "ArtId": "$ArtId" },
        "tcount": { "$sum": 1 },
        "ttags": { "$push": "$tags" }
    }},

    // Unwind twice because "ttags" is now an array of arrays
    { "$unwind": "$ttags" },
    { "$unwind": "$ttags" },

    // Now use $addToSet to get the distinct values        
    { "$group": {
        "_id": "$_id",
        "tcount": { "$first": "$tcount" },
        "tags": { "$addToSet": "$ttags" }
    }},

    // Optionally $project to get the fields out of the _id key
    { "$project": {
        "_id": 0,
        "Host": "$_id.Host",
        "ArtId": "$_id.ArtId",
        "count": "$tcount",
        "tags": "$ttags"
    }}
])

Ostatni bit z $project jest tam również, ponieważ użyłem „tymczasowych” nazw dla każdego z pól na innych etapach potoku agregacji. Dzieje się tak, ponieważ istnieje optymalizacja w $project który „kopiuje” pola z istniejącego etapu w kolejności, w jakiej pojawiły się „przed” dodaniem „nowych” pól do dokumentu.

W przeciwnym razie wynik wyglądałby następująco:

{  "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }

Gdzie pola nie są w tej samej kolejności, jak mogłoby się wydawać. To naprawdę trywialne, ale dla niektórych ma znaczenie, więc warto wyjaśnić, dlaczego i jak sobie z tym poradzić.

Więc $unwind wykonuje pracę, aby zachować elementy rozdzielone, a nie w tablicach, i wykonując $group pierwszy pozwala uzyskać „liczbę” wystąpień klawisza „grupowanie”.

$first użyty później operator „zachowuje” tę wartość „count”, ponieważ została „zduplikowana” dla każdej wartości obecnej w tablicy „tags”. To i tak ta sama wartość, więc to nie ma znaczenia. Po prostu wybierz jeden.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB:upsert sub-dokument

  2. MongoDB $pop

  3. Jak mogę przechowywać porę dnia w MongoDB? Jako ciąg? Podaj dowolny rok/miesiąc/dzień?

  4. Podstawy replikacji łańcucha MongoDB

  5. Spring Data Mongo - zastosuj unikalne pola kombinacji w osadzonym dokumencie