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

$svolgi un oggetto nel framework di aggregazione

Non è possibile eseguire il tipo di calcolo che stai descrivendo con il framework di aggregazione e non perché non c'è $unwind metodo per non array. Anche se gli oggetti persona:valore fossero documenti in un array, $unwind non sarebbe d'aiuto.

La funzionalità "raggruppa per" (sia in MongoDB che in qualsiasi database relazionale) viene eseguita sul valore di un campo o di una colonna. Raggruppiamo per valore di campo e somma/media/ecc in base al valore di un altro campo.

Un semplice esempio è una variante di ciò che suggerisci, il campo delle valutazioni è stato aggiunto alla raccolta di articoli di esempio, ma non come una mappa dall'utente alla valutazione, ma come una matrice come questa:

{ title : title of article", ...
  ratings: [
         { voter: "user1", score: 5 },
         { voter: "user2", score: 8 },
         { voter: "user3", score: 7 }
  ]
}

Ora puoi aggregarlo con:

[ {$unwind: "$ratings"},
  {$group : {_id : "$ratings.voter", averageScore: {$avg:"$ratings.score"} } } 
]

Ma questo esempio strutturato come lo descrivi sarebbe simile a questo:

{ title : title of article", ...
  ratings: {
         user1: 5,
         user2: 8,
         user3: 7
  }
}

o anche questo:

{ title : title of article", ...
  ratings: [
         { user1: 5 },
         { user2: 8 },
         { user3: 7 }
  ]
}

Anche se potessi $unwind questo, non c'è niente su cui aggregare qui. A meno che tu non conosca l'elenco completo di tutte le possibili chiavi (utenti), non puoi fare molto con questo. [*]

Uno schema DB relazionale analogo a quello che hai sarebbe:

CREATE TABLE T (
   user1: integer,
   user2: integer,
   user3: integer
   ...
);

Non è quello che si fa, invece si fa così:

CREATE TABLE T (
   username: varchar(32),
   score: integer
);

e ora aggreghiamo usando SQL:

select username, avg(score) from T group by username;

Esiste una richiesta di miglioramento per MongoDB che potrebbe consentirti di farlo nel framework di aggregazione in futuro:la possibilità di proiettare valori su chiavi e viceversa. Nel frattempo, c'è sempre mappa/riduci.

[*] C'è un modo complicato per farlo se conosci tutte le chiavi univoche (puoi trovare tutte le chiavi univoche con un metodo simile a questo) ma se conosci tutte le chiavi puoi anche eseguire una sequenza di query del form db.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1}) per ogni utenteX che restituirà tutte le sue valutazioni e puoi sommarle e fare una media abbastanza semplicemente piuttosto che fare una proiezione molto complessa che il framework di aggregazione richiederebbe.