2015-10-09 29 views
5

Ho appena iniziato ad imparare MongoDB e non riesco a trovare una soluzione per il mio problema.Proiezione di array multidimensionale MongoDB

Got quel documento:

> db.test.insert({"name" : "Anika", "arr" : [ [11, 22],[33,44] ] }) 

Si prega di notare il campo "arr", che è un array multidimensionale.

Ora sto cercando una query che restituisce solo il valore di arr [0] [1] che è 22. Ho provato a farlo utilizzando $ slice, tuttavia non so come indirizzare il secondo dimensione con quella.

> db.test.find({},{_id:0,"arr":{$slice: [0,1]}}) 
{ "name" : "ha", "arr" : [ [ 11, 22 ] ] } 

Ho anche provato

> db.test.find({},{_id:0,"arr":{$slice: [0,1][1,1]}}) 
{ "name" : "ha", "arr" : [ [ 11, 22 ] ] } 

L'output desiderato sarebbe o

22 

o

{"arr":[[22]]} 

Grazie

01.235.

EDIT:

Dopo aver letto i commenti che penso che ho semplificato i dati di esempio troppo e devo fornire maggiori informazioni:

  1. ci sono molti altri documenti nella collezione come quella che ho fornito . Ma hanno tutti la stessa struttura.
  2. Non ci sono più elementi di un array di solo due
  3. Nel mondo reale l'array contiene davvero testi lunghi (500kb-1MB), quindi è molto espansiva per trasmettere i dati interi al client.
  4. Prima dell'aggregazione farò una query dal campo 'nome'. Solo saltato nell'esempio per semplicità.
  5. Gli indici di riferimento sono variabili, quindi a volte devo conoscere il valore di arr [0] [1], la prossima volta è arr [1] [4]

esempio dati :

> db.test.insert({"name" : "Olivia", "arr" : [ [11, 22, 33, 44],[55,66,77,88],[99] ] }) 
> db.test.insert({"name" : "Walter", "arr" : [ [11], [22, 33, 44],[55,66,77,88],[99] ] }) 
> db.test.insert({"name" : "Astrid", "arr" : [ [11, 22, 33, 44],[55,66],[77,88],[99] ] }) 
> db.test.insert({"name" : "Peter", "arr" : [ [11, 22, 33, 44],[55,66,77,88],[99] ] }) 

esempio di query:

> db.test.find({name:"Olivia"},{"arr:"...}) 

risposta

2

È possibile utilizzare il framework di aggregazione:

db.test.aggregate([ 
    { $unwind: '$arr' }, 
    { $limit: 1 }, 
    { $project: { _id: 0, arr: 1 } }, 
    { $unwind: '$arr' }, 
    { $skip: 1 }, 
    { $limit: 1 } 
]) 

Returns:

{ "arr": 22 } 

Edit: Il manifesto originale ha modificato la mia soluzione per soddisfare le sue esigenze e si avvicinò con la seguente:

db.test.aggregate([ 
    { $match: { name:"Olivia" } }, 
    { $project: { _id: 0,arr: 1 } }, 
    { $unwind: '$arr' }, 
    { $skip: 1 }, 
    { $limit:1 }, 
    { $unwind: "$arr" }, 
    { $skip: 2 }, 
    { $limit: 1 } 
]) 

Questa interrogazione si tradurrà in { arr: 77 } dati i dati estesi forniti dall'OP. Si noti che $ skip e $ limit sono necessari per selezionare gli elementi giusti nella gerarchia degli array.

+0

Questo non può funzionare su null'altro che un singolo documento. Sicuramente '$ skip' e' $ limit' "simulano" posizioni indicizzate, ma una volta che '$ unwind' su più documenti di raccolta diventa irrilevante. –

+0

Funzionerà se l'output desiderato ** è ** per un singolo documento. È sempre possibile ottenere un solo documento desiderato usando '$ match'. –

+0

Non sarà mai realisticamente. Si tratta di dare alle persone esempi "reali" che possono davvero utilizzare. I singoli casi di documenti sono meglio codificati nel client come ho affermato nella mia risposta. –

0

Il modulo $slice non richiede array multidimensionali. Ogni array viene considerato singolarmente e pertanto non è supportato in questo modo dall'attuale $slice.

quanto tale, esso è in realtà fatto molto più breve sui "primi" valori indicizzati e "ultimi" che è stato suggerito di usare .aggregate(), e attualmente:

db.test.aggregate([ 
    { "$unwind": "$arr" }, 
    { "$group": { 
     "_id": "$_id", 
     "arr": { "$first": "$arr" } 
    }}, 
    { "$unwind": "$arr" }, 
    { "$group": { 
     "_id": "$_id", 
     "arr": { "$last": "$arr" } 
    }} 
]) 

Ma nelle versioni future di MongoDB (attualmente lavora in ramo di sviluppo 3.18 al momento di scrivere) si dispone $arrayElemAt come operatore per il quadro di aggregazione, che funziona così:

db.test.aggregate([ 
    { "$project": { 
     "arr": { 
      "$arrayElemAt": [ 
       { "$arrayElemAt": [ "$arr", 0 ] }, 
       1 
      ] 
     } 
    }} 
]) 

Entrambi praticamente giunti alla stessa { "arr": 22 } risultato, anche se il il futuro modulo disponibile funziona in modo piuttosto flessibile sui valori dell'indice dell'array, piuttosto che sul primo e sull'ultimo.

+0

È bello sapere '$ arrayElemAt'! Grazie per la condivisione. Tuttavia, ho una domanda sull'utilizzo degli operatori di aggregazione. '$ Group' è più costoso rispetto a' $ limit' nel mio esempio? –

+0

Inoltre, se non si conosce il numero di elementi in un array, probabilmente non si sarà in grado di usare '$ first' e' $ last'. Quindi l'uso di '$ limit' sembra più versatile per me. –

+1

@DmytroShevchenko Nope. Più fasi di pipeline di aggregazione == le più costose. PUNTO. Meno è meglio. Ovviamente i nuovi operatori (quando diventano disponibili) significano una singola fase, che è quindi il miglior risultato. In tutta onestà, se questa è la completa complessità di ciò che stai chiedendo, allora il quadro di aggregazione non è "presente" la risposta. Fatelo invece nel codice client, che è molto più efficiente. –

Problemi correlati