2015-10-09 14 views
5

Właśnie zacząłem uczyć się MongoDB i nie mogę znaleźć rozwiązania dla mojego problemu.Projekcja wielowymiarowych macierzy MongoDB

Got tego dokumentu:

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

Zwróć uwagę pole "arr", która jest wielowymiarowa tablica.

Teraz szukam zapytania, które zwraca tylko wartość arr [0] [1], która jest 22. Próbowałem to osiągnąć, używając $ slice, jednak nie wiem jak adresować drugie z tym wymiarem.

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

Próbowałem też

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

pożądany wynik byłby albo

22 

lub

{"arr":[[22]]} 

Dziękuję


EDIT:

Po przeczytaniu komentarzy myślę, że mam uproszczona przykładowe dane za dużo i muszę dostarczyć więcej informacji:

  1. Istnieje wiele dokumentów w kolekcja podobna do tej, którą dostarczyłem. Ale wszystkie mają taką samą strukturę.
  2. Istnieje więcej niż tylko elementy tablicy dwa
  3. w realnym świecie tablica zawiera bardzo długie teksty (500kb-1MB), więc jest bardzo ekspansywny do przesyłania całych danych do klienta.
  4. Przed agregacją zrobię zapytanie przez pole "nazwa". Po prostu pominąłem to w przykładzie ze względu na prostotę.
  5. Indeksy docelowymi są zmienne, to czasami trzeba znać wartość ARR [0] [1], następne jest ARR [1] [4]

przykład dane :

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

przykład zapytania:

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

Odpowiedz

2

można użyć ramy agregacji:

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

Powroty:

{ "arr": 22 } 

Edit: Oryginalny plakat zmienił moje rozwiązanie do zaspokojenia jego potrzeb i wymyślił następujące:

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

To zapytanie spowoduje { arr: 77 } biorąc pod uwagę rozszerzone dane dostarczone przez PO. Zauważ, że $ skip i $ limit są potrzebne, aby wybrać właściwe elementy w hierarchii tablic.

+0

To nie może działać na niczym innym niż pojedynczy dokument. Z pewnością '$ skip' i' $ limit' "symulują" indeksowane pozycje, ale gdy "rozwiniesz" w wielu dokumentach kolekcji, stanie się to nieistotne. –

+0

Będzie działać, jeśli żądane wyjście ** wynosi ** dla pojedynczego dokumentu. Zawsze można uzyskać tylko jeden pożądany dokument za pomocą '$ match'. –

+0

Nigdy nie będzie realistycznie. Chodzi o dawanie ludziom "prawdziwych" przykładów, których naprawdę mogą używać. Przypadki pojedynczego dokumentu są lepiej zakodowane w kliencie, jak stwierdziłem w mojej odpowiedzi. –

0

Formularz $slice, o który pytasz, nie zawiera macierzy wielo-wymiarowych. Każda tablica jest traktowana indywidualnie i dlatego nie jest obsługiwana w ten sposób przez bieżący numer $slice.

Jako taka jest ona rzeczywiście zrobić dużo krótszy o indeksowanych „pierwszy” i „ostatni” wartości niż sugerowano użyciu .aggregate(), a obecnie:

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

Ale w przyszłych wydaniach MongoDB (obecnie pracuje w gałąź rozwojowa 3.18 jako o piśmie) masz $arrayElemAt jako operator dla ram agregacji który działa tak:

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

Zarówno w zasadzie dojść do tego samego { "arr": 22 } rezultacie, chociaż dostępna w przyszłości forma działa dość elastycznie na podstawie wartości indeksu tablicy, a nie pierwszego i ostatniego.

+0

Dobrze wiedzieć o '$ arrayElemAt'! Dziękuję za udostępnienie. Mam pytanie dotyczące wykorzystania przez ciebie operatorów agregujących. Czy w moim przykładzie "$ group" nie jest droższy niż "$ limit"? –

+0

Ponadto, jeśli nie znasz liczby elementów w tablicy, prawdopodobnie nie będziesz w stanie użyć '$ first' i' $ last'. Dlatego użycie '$ limit' wygląda dla mnie bardziej wszechstronnie. –

+1

@DmytroShevchenko Nie. Im więcej etapów potoku agregacji == tym drożej. KROPKA. Mniej znaczy lepiej. Oczywiście nowi operatorzy (gdy staną się dostępni) oznaczają pojedynczy etap, który jest zatem najlepszym wynikiem. Szczerze mówiąc, jeśli jest to pełna złożoność tego, o co prosisz, struktura agregacji nie jest "obecnie" odpowiedzią. Zrób to w kodzie klienta, co jest znacznie bardziej wydajne. –

Powiązane problemy