2015-07-08 17 views
7

Questa domanda - Is it possible to get a slice of a slice in Mongo? illustra come ottenere una porzione di una sezione in Mongo. In breve, utilizzare una catena di aggregazione su $unwind, $skip, $limit, $unwind, $skip, $limit e $group.

La mia domanda è come fare questo su una raccolta di più documenti. Voglio tagliare l'array annidato all'interno di ognuno. Una volta I $unwind, tuttavia, $skip e hanno senso solo in base alla numerazione del primo array.

C'è un modo per eseguire questo tipo di pipeline su ciascun documento in una raccolta, piuttosto che sulla raccolta nel suo insieme? È quello che sto cercando di fare nella pipeline di aggregazione? È chiaramente possibile utilizzare Map-Reduce, ma è più lento farlo che eseguire le query n + 1 su $unwind ogni documento singolarmente.


Modifica

Di seguito è un record di esempio.

{ 
    title: "Text Title" 
    vtitle: "Text Version Title" 
    text: [[["Book1, Chapter 1, Line 1", "Book1, Chapter 1, Line 2"],["Book 1, Chapter 2, Line 1"]],[["Book 2, Chapter 1, Line 1]]] 
} 

Il record qui è il testo di un grande libro, memorizzato come una matrice di profondità 3. Ci possono essere molti diversi vtitle per lo stesso title e lo text può essere abbastanza grande.

Mi piacerebbe selezionare un piccolo pezzetto di testo contenuto, identificato da indici, da ogni libro in una raccolta di molti libri - una porzione di una porzione di ogni singolo documento restituito.

Ad esempio, i parametri di ingresso del [3,3] tornavano dischi come:

{ "text" : ["Book 4, Chapter 4, Line 1", "Book 4, Chapter 4, Line 2", ...] } 
+0

Attualmente, sto trovando che devo eseguire n + 1 query - 1 per ottenere l'elenco dei documenti, e quindi uno con la pipeline di aggregazione per ogni documento. – Laizer

+1

Qual è il tuo esempio attuale? Che ne dici di modificare la tua domanda per mostrare alcuni documenti di esempio e il tuo caso reale che vuoi raggiungere. Questo dà quindi qualcosa a cui rispondere con un esempio piuttosto che solo parole o ipotesi. –

+0

Aggiunto l'esempio sopra. – Laizer

risposta

1

TL; DR

Penso che la risposta breve sia che non si può davvero fare ciò che si vuole ancora. Le opzioni attuali sarebbero aspettare fino alla v3.1 o modificarlo con un'aggregazione group (ma ho il sospetto che sia troppo lento per le tue esigenze).

Giustificazione

anche se non è del tutto chiaro il risultato esatto che si desidera ottenere, l'intenzione è chiaramente che si vuole essere in grado di trovare una serie di documenti corrispondenti nella vostra collezione e trasformare (cioè mappa) i documenti (affettando l'array nidificato per produrre una lista di stringhe piatte). La ricerca è irrilevante in quanto è possibile farlo prima o dopo la mappatura e comunque soddisfare i propri vincoli. Pertanto parlerò solo della mappatura.

Questo è un caso di utilizzo naturale per MapReduce, ma è esplicitamente escluso dalle risposte consentite. Quindi, ci sono 3 opzioni, che prenderò a turno.

1) Interroga

Dal momento che avete annullato più query, l'unica opzione è quella di mappare i dati all'interno della richiesta. Questo è gestito attraverso the projection operators. Questi non funzioneranno.

  1. Mentre c'è un operatore $slice qui, non gestisce gli array annidati.
  2. L'operatore $ consente solo di prendere la prima voce in una matrice, che non è sufficiente per ottenere una posizione arbitraria nell'array.
  3. $elemMatch consente di ottenere solo un campo da un array, che è anche insufficiente per le proprie esigenze.

Inoltre non è possibile proiezioni a catena su una query, quindi non è possibile mettere proiezioni multiple insieme in qualche modo astuto per tagliare i dati più volte.

In breve, questo non funzionerà.

2) Aggregazione gasdotto

Purtroppo, non v'è un operatore porzione per il gasdotto di aggregazione fino v3.1. Si è quindi limitato a $project o forse a un uso astuto degli altri operatori (come per l'articolo collegato).

Prendendo prima l'operatore di proiezione. Mentre è possibile operate on array fields, si è limitati ad ottenere solo la dimensione per ora. Si potrebbe provare a utilizzare set logic ma questo è intrinsecamente non ordinato, quindi non è possibile ottenere la voce Nth qui.

Pertanto un'operazione diretta non funziona. Quindi possiamo migliorare l'articolo che hai collegato? Questa soluzione alternativa funziona solo per un documento perché non è necessario distinguere tra più documenti. Puoi quindi permetterti di disfare una matrice per creare un elenco più grande di documenti e quindi utilizzare le operazioni di portata a livello di documento per eseguire in modo efficace il taglio.

Purtroppo, questo cade quando è necessario trovare l'inizio della prossima documentazione originale nella tua ultima lista esaurita. Non esiste una combinazione di operators che consente di enumerare l'array non svolto e quindi selezionare tale enumerazione e il documento originale.

  1. $unwind espande la matrice, ma non ti dà un indice per voi per abbinare successivamente e $ salto fornisce alcun modo per passare al successivo documento con una condizione di corrispondenza.
  2. $redact ti tiene ancora nell'ambito dei tuoi documenti originali, ma poi subisce lo stesso problema di $project che non può operare sull'array nidificato.

In breve, anche questo è un busto.

3) l'aggregazione Gruppo

ero sul punto di rinunciare a questo punto, poi ho notato group aggregation. È possibile creare un filtro per i documenti corrispondenti, ma fornire quindi una funzione JavaScript arbitraria con finalize per trasformare tali dati prima di restituirli.Ciò significa che si dovrebbe essere in grado di emettere un comando come questo:

db.runCommand(
    { 
    group: 
     { 
     ns: 'books', 
     key: { title: 1, text: 1 }, 
     cond: { }, 
     $reduce: function (curr, result) { }, 
     initial: { }, 
     finalize: function(result) { 
      // Insert your code here to slice the array - e.g. 
      result.text = result.text[0][0] 
     } 
     } 
    }) 

Naturalmente, come documentato here questo non funziona se il database è sharded, i risultati sono più grandi di 16 MB o se hai più di 20.000 documenti (poiché ognuno è ora una chiave per l'aggregazione). È anche molto lento quando il set di dati diventa grande.

Problemi correlati