sql >> Database teknologi >  >> NoSQL >> MongoDB

Sammenkæd strengværdier i matrix i et enkelt felt i MongoDB

I Moderne MongoDB-udgivelser kan du. Du kan stadig ikke "direkte" anvende en matrix til $concat , men du kan bruge $reduce at arbejde med array-elementerne og producere dette:

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

I kombination med $indexOfArray for at ikke "sammenkæde" med "_" understreg, når det er det "første" indeks i arrayet.

Også mit ekstra "ønske" er blevet besvaret med $sum :

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

Denne slags bliver hævet lidt generelt med aggregeringsoperatorer, der tager en række elementer. Forskellen her er, at det betyder en "array" af "agumenter" tilvejebragt i den kodede repræsentation i modsætning til et "array-element", der findes i det aktuelle dokument.

Den eneste måde, du virkelig kan lave den slags sammenkædning af elementer inden for et array, der er til stede i dokumentet, er at lave en slags JavaScript-indstilling, som med dette eksempel i mapReduce:

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

Selvfølgelig, hvis du faktisk ikke samler noget, så er den muligvis bedste tilgang blot at udføre den "join"-operation i din klientkode i efterbehandlingen af ​​dine forespørgselsresultater. Men hvis det skal bruges til et eller andet formål på tværs af dokumenter, så vil mapReduce være det eneste sted, du kan bruge det.

Jeg kunne tilføje, at "for eksempel" ville jeg elske, at sådan noget virkede:

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

Og samlet set:

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

Men det virker ikke på den måde, fordi $add forventer argumenter i modsætning til en matrix fra dokumentet. Suk! :(. En del af "by design"-begrundelsen for dette kunne hævdes, at "bare fordi" det er en matrix eller "liste" af enkeltværdier, der overføres fra resultatet af transformationen, er det ikke "garanteret", at de er faktisk "gyldige" singulære numeriske typeværdier, som operatøren forventer. I hvert fald ikke ved de nuværende implementerede metoder til "typekontrol".

Det betyder, at vi stadig skal gøre dette:

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

Og desværre ville der heller ikke være nogen måde at anvende en sådan grupperingsoperator til at sammenkæde strenge.

Så du kan håbe på en form for ændring på dette, eller håbe på en ændring, der gør det muligt at ændre en eksternt omfangsvariabel inden for rammerne af et $map operation på en eller anden måde. Endnu bedre en ny $join operation ville også være velkommen. Men disse eksisterer ikke i skrivende stund, og vil formentlig ikke i nogen tid fremover.



  1. Hvad er den mest effektive node.js inter-proces kommunikationsbibliotek/metode?

  2. Opdater MongoDB-samling ved hjælp af $toLower

  3. Meteor:forskel mellem navne på samlinger, variabler, publikationer og abonnementer?

  4. importerer JSON til mongoDB ved hjælp af pymongo