2015-07-03 19 views
7

Zaimportowałem trochę niepotrzebnych danych XML do bazy danych Mongo. Każdy dokument zawiera zagnieżdżone dokumenty podrzędne na głębokość około 5-10. Chciałbym znaleźć() dokumenty, które mają szczególną wartość konkretnego pola, gdzie pole może pojawić się na dowolnej głębokości w pod-dokumentach (i może pojawić się wiele razy).Jak znaleźć nazwę pola MongoDB na dowolnej głębokości

Obecnie przeciągam każdy dokument do Pythona, a następnie przeszukuję ten słownik, ale byłoby miło, gdybym mógł podać prototyp filtra, w którym baza danych zwróciłaby tylko dokumenty, które mają konkretną wartość nazwy pola, gdzieś w ich zawartości .

Oto przykład dokument:

{ 
    "foo": 1, 
    "bar": 2, 
    "find-this": "Yes!", 
    "stuff": { 
     "baz": 3, 
     "gobble": [ 
      "wibble", 
      "wobble", 
      { 
       "all-fall-down": 4, 
       "find-this": "please find me" 
      }     
     ], 
     "plugh": { 
      "plove": { 
       "find-this": "Here too!" 
      } 
     } 
    } 
} 

Tak, chciałbym, aby znaleźć dokumenty, które mają „Find-owego” pola, oraz (jeśli to możliwe), aby móc znaleźć dokumenty, które mają działanie szczególną wartość pola "znajdź-to".

+0

Święty server-side scripting, Batman! Nie miałem pojęcia, że ​​możesz uruchomić JS w bazie danych! To naprawdę fajne, a twoje rozwiązanie ma sens. Dziękuję bardzo! –

+0

Och, wiesz co?Założę się, że możesz zrobić find() z klauzulą ​​"lub" $ where: niech baza znajdzie "key-to-search" i "value-to-search" używając własnych (szybkich) mechanizmów, dla których klucz jest najwyższy poziom i udostępnia funkcję JS rekursywnego wyszukiwania, która będzie używana we wszystkich węzłach, w których "klucz do wyszukiwania" nie znajduje się na najwyższym poziomie. Dodam to do tego pytania, jeśli uda mi się je uruchomić. –

Odpowiedz

7

Masz rację w pewnym stwierdzeniu dokumentu BSON nie jest dokumentem XML. Ponieważ XML jest ładowany do struktury drzewa, która składa się z "węzłów", wyszukiwanie na dowolnym kluczu jest dość łatwe.

Dokument MonoDB nie jest tak prosty w przetwarzaniu, a jest to "baza danych" pod wieloma względami, więc zazwyczaj oczekuje się pewnej "jednolitości" lokalizacji danych, aby ułatwić zarówno indeksowanie "i wyszukaj.

Niemniej jednak można tego dokonać. Ale oczywiście oznacza to rekursywny proces wykonywany na serwerze, a to oznacza przetwarzanie JavaScriptu z $where.

Jako podstawowy przykład powłoki, ale ogólny function jest właśnie argument ciąg do operatora $where wszędzie:

db.collection.find(
    function() { 
    var findKey = "find-this", 
     findVal = "please find me"; 

    function inspectObj(doc) { 
     return Object.keys(doc).some(function(key) { 
     if (typeof(doc[key]) == "object") { 
      return inspectObj(doc[key]); 
     } else { 
      return (key == findKey && doc[key] == findVal); 
     } 
     }); 
    } 
    return inspectObj(this); 
    } 
) 

Więc w zasadzie, test klawiszy znajdujących się w obiekcie, aby sprawdzić, czy odpowiadają one pożądany "nazwa pola" i treść. Jeśli jeden z tych kluczy stanie się "obiektem", powróć do funkcji i sprawdź ponownie.

JavaScript .some() upewnia się, że znaleziony "pierwszy" wynik powróci z funkcji wyszukiwania, dając wynik: true i zwróci obiekt, w którym "klucz/wartość" był obecny na pewnej głębokości.

Należy pamiętać, że $where zasadniczo oznacza przechodzenie całej kolekcji, chyba że istnieje inny prawidłowy filtr kwerendy niż można zastosować do "indeksu" w kolekcji.

Używaj więc ostrożnie lub w ogóle nie pracuj, po prostu przepracuj dane w bardziej funkcjonalną formę.

Ale to da ci równowagę.

2

Oto jeden z przykładów, który używam do rekurencyjnego wyszukiwania dla klucz-wartość w dowolnym miejscu struktury dokumentu:

db.getCollection('myCollection').find({ 

    "$where" : function(){ 

     var searchKey = 'find-this'; 
     var searchValue = 'please find me'; 

     return searchInObj(obj); 

     function searchInObj(obj){        
      for(var k in obj){  
      if(typeof obj[k] == 'object' && obj[k] !== null){ 
       if(searchInObj(obj[k])){ 
       return true; 
       } 
      } else { 
       if(k == searchKey && obj[k] == searchValue){ 
       return true; 
       } 
      }   
      }       
      return false; 
     }  
    }  
})