sql >> Databáze >  >> NoSQL >> MongoDB

Jak sloučit pole pole v dokumentu v agregaci Mongo

TLDR;

Moderní verze by měly používat $reduce pomocí $setUnion za počáteční $group jak je znázorněno:

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

Měli jste pravdu, když jste našli $addToSet operátor, ale při práci s obsahem v poli obecně potřebujete zpracovat pomocí $unwind za prvé. To "denormalizuje" položky pole a v podstatě vytvoří "kopii" nadřazeného dokumentu s každým záznamem pole jako singulární hodnotou v poli. To je to, co potřebujete, abyste se vyhnuli chování, které vidíte, aniž byste to použili.

Váš "počet" však představuje zajímavý problém, ale lze jej snadno vyřešit pomocí "dvojitého uvolnění" po úvodní $group operace:

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

Poslední bit s $project je tam také proto, že jsem použil "dočasné" názvy pro každé z polí v jiných fázích agregačního kanálu. Důvodem je optimalizace v $project že „zkopíruje“ pole z existující fáze v pořadí, v jakém se již objevila „před“ přidáním jakýchkoli „nových“ polí do dokumentu.

Jinak by výstup vypadal takto:

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

Kde pole nejsou ve stejném pořadí, jak si možná myslíte. Opravdu triviální, ale pro některé lidi na tom záleží, takže stojí za to vysvětlit proč a jak s tím zacházet.

Takže $unwind dělá práci, aby položky zůstaly oddělené a ne v polích, a dělá $group první vám umožňuje získat "počet" výskytů klíče "seskupení".

$first operátor použitý později "uchová" tuto hodnotu "count", protože se právě "duplikoval" pro každou hodnotu přítomnou v poli "tags". Stejně má všechno stejnou hodnotu, takže na tom nezáleží. Stačí si vybrat jednu.




  1. Redis - nějaký způsob, jak spustit událost, když se hodnota již aktivně nezapisuje?

  2. doRedis s podivnou chybou připojení soketu v Ubuntu Linux, R a RStudio

  3. Jak vytvořit schéma Mongoose s polem ID objektů?

  4. Špatný výpočet vzdálenosti s MongoDB