2015-09-10 7 views
5

Mam kolekcję MongoDb zawierającą 284.116 tweetów. Problem polega na tym, że pole "autor" w niektórych obiektach znajduje się w typie obiektu, ale w innych obiektach - to pole "autora" - jest typu tablicowego. Problem polega więc na tym, że chcę filtrować, które z nich to Array, a które to Object.

Na przykład: Typ pola autora jest obiektem.

{ 
    "_id" : ObjectId("55edfbd11a87d41d987a6dc1"), 
    "tweet" : "Back in my dorm, yay!", 
    "uri" : "https://twitter.com/natalylug0/status/640994018529181696", 
    "date" : "2015-09-08 00:04:17", 
    "country" : "U.S.A.", 
    "city" : "Texas", 
    "state" : "Dallas", 
    "author" : { 
     "username" : "Nataly", 
     "uri" : "https://twitter.com/natalylug0", 
     "screenname" : "natalylug0" 
    } 
} 

a drugi: typu polowego autora jest tablicą.

{ 
    "_id" : ObjectId("55ee3a00e11fbb1030d659fe"), 
    "author" : [ 
     { 
      "username" : "Relapsed Shini", 
      "uri" : "https://twitter.com/iPictoraL", 
      "screenname" : "iPictoraL" 
     } 
    ], 
    "tweet" : "@zumbiezuza ily zoeeeeeeee", 
    "uri" : "https://twitter.com/iPictoraL/status/641060812140900352", 
    "date" : "2015-09-08 01:29:42", 
    "country" : "U.S.A.", 
    "city" : "Texas", 
    "state" : "Dallas" 
} 

Więc wykonywane zapytanie tak:

db.getCollection('tweets').find({ author: { $type: 4} }) 

I co mam jest

Fetched 0 record(s) 

Ale jeśli wykonać $ typ: 3 uzyskać 284.116 wartości, które jest ta sama wartość rozmiaru tej kolekcji.

Moje pytanie brzmi: jak mogę filtrować obiekty, które pola "autor" zawierają tablice.

Odpowiedz

15

Właściwie istnieje „haczyka” wymienione w dokumentacji $type konkretnie o macierzach:

Kiedy stosuje się do tablic, $ typ pasuje dowolny element wewnętrzny, który jest od określonego typu. Bez projekcji oznacza to, że cała tablica będzie pasować, jeśli dowolny element ma odpowiedni typ. W przypadku projekcji wyniki będą zawierały tylko te elementy żądanego typu.

Oznacza to, że zamiast sprawdzać, czy "sam element" jest w tablicy, to, co faktycznie jest testowane, jest "wewnętrznym elementem" tablicy, aby zobaczyć, jaki to jest.

Teraz sama dokumentacja sugeruje test JavaScript z $where:

.find({ "$where": "return Array.isArray(this.author)" }) 

Ale myślę, że to dość straszne, jak tam jest lepszy sposób.

Sztuką jest w "dot notation", gdzie można poprosić o elemencie 0 indeksu tablicy do $exists

.find({ "author.0": { "$exists": true } }) 

który jest tylko podstawowa sprawa, że ​​jeśli „0-cie” pierwiastek występuje wówczas pole jest obecny i dane są zatem tablicą.

Po zrozumieniu tego logicznego założenia jest to dość prosty test. Jedyną rzeczą, której nie można dopasować, jest "prawdziwie pusta" tablica, w którym to przypadku możesz w razie potrzeby wrócić do alternatywnej wersji JavaScript. Ale to może rzeczywiście korzystać z indeksu, więc byłoby lepiej skorzystać z tej ostatniej formy.

+0

Jeśli twój kod zawiera błąd i wstawia obiekty wyglądające jak tablice, proponowany '" autor.0 ": {" $ exists ": true}' nie zadziała. Mówię o '{0:" bla "}' – Danielo515

1

Oto lepszy sposób zrobienia tego, o co prosiłaś; to rzeczywiście sprawdzić, czy dany obszar posiada wartość typu tablicy:

.find({ "author": { "$gte": [] } }) 

$ funkcjonalność typu MongoDB dla tablic, chociaż dobrze udokumentowane, jest IMO niespójne z innymi kontrolami $ typ, i oczywiście nie działa w tym przypadku użycia, ale od około 2.6 można użyć powyższej kwerendy, aby sprawdzić, czy wartość jest tablicą (pustą lub nie).

Mówię, że jest "lepszy" niż aktualnie wybrana odpowiedź, ponieważ wykonywanie kodu za pomocą $ where nie jest zalecane, chyba że standardowe konstrukcje zapytań naprawdę nie mogą wykonać zadania.

Aby opracować, $ where nie jest zalecane ze względu na wydajność poprzez brak możliwości używania indeksów w wykonywanym kodzie. Więcej szczegółów: https://docs.mongodb.com/manual/reference/operator/query/where/#considerations

Ponadto, jeśli chcesz sprawdzić niepustymi tablic konkretnie, użyj tego:

.find({ "author": { "$gt": [] } }) 

Technicznie ten jest również lepszy niż obecny odpowiedź odpowiadająca $ istnieje rozwiązanie, ponieważ pole może zawierać obiekt inny niż tablicowy z polem o nazwie "0" i pasować jako "niepustą tablicę", co jest w tym przypadku złe.