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

Zřetězte řetězcové hodnoty v poli do jednoho pole v MongoDB

Ve verzích Modern MongoDB můžete. Stále nemůžete "přímo" použít pole na $concat , ale můžete použít $reduce pracovat s prvky pole a vytvořit toto:

db.collection.aggregate([
  { "$addFields": {
    "values": { 
      "$reduce": {
        "input": "$values",
        "initialValue": "",
        "in": {
          "$cond": {
            "if": { "$eq": [ { "$indexOfArray": [ "$values", "$$this" ] }, 0 ] },
            "then": { "$concat": [ "$$value", "$$this" ] },
            "else": { "$concat": [ "$$value", "_", "$$this" ] }
          }    
        }
      }        
    }
  }}
])

Samozřejmě v kombinaci s $indexOfArray aby ne "concatenate" s "_" podtržítko, když je to "první" index pole.

Také moje další "přání" bylo zodpovězeno $sum :

db.collection.aggregate([
  { "$addFields": {
    "total": { "$sum": "$items.value" }
  }}
])

Tento druh se obecně trochu zvyšuje s agregačními operátory, které berou řadu položek. Rozdíl je v tom, že to znamená „pole“ „agumentů“ poskytnutých v kódované reprezentaci na rozdíl od „prvku pole“ přítomného v aktuálním dokumentu.

Jediný způsob, jak můžete skutečně provést druh zřetězení položek v poli přítomné v dokumentu, je provést nějakou volbu JavaScriptu, jako v tomto příkladu v mapReduce:

db.collection.mapReduce(
    function() {
        emit( this._id, { "values": this.values.join("_") } );
    },
    function() {},
    { "out": { "inline": 1 } }
)

Samozřejmě, pokud ve skutečnosti nic neagregujete, pak možná nejlepším přístupem je jednoduše provést operaci „spojení“ ve vašem klientském kódu při následném zpracování výsledků dotazu. Ale pokud je třeba jej použít k nějakému účelu napříč dokumenty, pak mapReduce bude jediným místem, kde jej můžete použít.

Mohl bych dodat, že „například“ bych byl rád, kdyby něco takového fungovalo:

{
    "items": [
        { "product": "A", "value": 1 },
        { "product": "B", "value": 2 },
        { "product": "C", "value": 3 }
    ]
}

A v souhrnu:

db.collection.aggregate([
    { "$project": {
        "total": { "$add": [
            { "$map": {
                "input": "$items",
                "as": "i",
                "in": "$$i.value"
            }}
        ]}
    }}
])

Ale takto to nefunguje, protože $add očekává argumenty na rozdíl od pole z dokumentu. Povzdech! :(. Část zdůvodnění „by design“ by mohla být argumentována tím, že „jen proto, že“ jde o pole nebo „seznam“ singulárních hodnot předávaných z výsledku transformace, není „zaručeno“, že jsou skutečně „platné“ singulární číselné hodnoty typu, které operátor očekává. Alespoň ne u současných implementovaných metod „kontroly typu“.

To znamená, že zatím musíme udělat toto:

db.collection.aggregate([
   { "$unwind": "$items" },
   { "$group": {
       "_id": "$_id",
        "total": { "$sum": "$items.value" }
   }}
])

A také by bohužel neexistoval způsob, jak použít takový seskupovací operátor ke zřetězení řetězců.

Můžete tedy doufat v nějakou změnu v tomto nebo doufat v nějakou změnu, která umožní změnit externě vymezenou proměnnou v rámci $map nějakým způsobem provozovat. Ještě lepší nový $join operace by byla také vítána. Ty však v době psaní neexistují a pravděpodobně ještě nějakou dobu nebudou.



  1. Jak udělat základní WATCH s StackExchange.Redis

  2. Jak nastavit useMongoClient (Mongoose 4.11.0)?

  3. Proč je výkon Redis SET lepší než GET?

  4. redis + gevent - Špatný výkon - co dělám špatně?