2015-09-10 17 views
5

Possiedo una raccolta MongoDb contenente 284.116 tweet. Il problema è che il campo "autore" in alcuni oggetti è nel tipo di oggetto, ma in altri oggetti - questo campo "autore" - sono nel tipo di matrice. Quindi il problema è che voglio filtrare quali sono Array e quali sono Object.

Ad esempio: Il tipo di campo dell'autore è oggetto.

{ 
    "_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" 
    } 
} 

E l'altro: tipo del campo autore è array.

{ 
    "_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" 
} 

Così ho eseguito query come questa:

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

E quello che ottengo è

Fetched 0 record(s) 

Ma se eseguire $ tipo: 3 ottengo 284.116 valori che è lo stesso valore di dimensione di questa collezione.

Quindi la mia domanda è, come posso filtrare gli oggetti che i campi "autore" contengono matrici.

risposta

15

in realtà c'è un "Beccato" elencati nella documentazione per $type specificamente sugli array:

Quando applicata agli array, $ type Seleziona ogni elemento interiore che è del tipo specificato. Senza proiezione ciò significa che l'intero array corrisponderà se qualche elemento ha il tipo giusto. Con la proiezione, i risultati includeranno solo quegli elementi del tipo richiesto.

Quindi ciò significa che piuttosto che rilevare se "l'elemento stesso" è nell'array, ciò che viene effettivamente testato è "l'elemento interno" dell'array per vedere di che tipo si tratta.

Ora la documentazione stesso suggerisce questo test JavaScript con $where:

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

Ma io credo che sia abbastanza orribile in quanto v'è un modo migliore.

Il trucco sta nel "dot notation", in cui si chiede l'elemento 0 indice della matrice per $exists

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

che è solo il caso di base che se l'elemento "0a" esiste quindi il campo è presente e i dati sono quindi una matrice.

Una volta compresa questa premessa logica, è un test piuttosto semplice. L'unica cosa che non può essere eguagliata da questo è un array "veramente vuoto", nel qual caso puoi ricorrere all'alternativa JavaScript, se necessario. Ma questo in realtà può usare un indice, quindi sarebbe preferibile usare l'ultima forma.

+0

Se il codice ha un bug e sta inserendo oggetti che assomigliano a matrici, il proposto "autore.0": {"$ exists": true} 'non funziona. Sto parlando di '{0:" bla "}' – Danielo515

1

Ecco un modo migliore per fare ciò che inizialmente richiesto; vale a controllare effettivamente se un certo campo contiene un valore di tipo matrice:

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

funzionalità di tipo $ di MongoDB per gli array, anche se ben documentato, è IMO incompatibile con tutti gli altri controlli $ tipo, e ovviamente non funziona per questo caso d'uso, ma dal 2.6 circa, è possibile utilizzare la query precedente per verificare se il valore è un array (vuoto o non).

Dico che questo è "migliore" della risposta correntemente selezionata, perché l'esecuzione del codice tramite $ dove non è raccomandato, a meno che i costrutti di query standard non siano realmente in grado di portare a termine il lavoro.

Per elaborare, $ dove non è consigliabile a causa delle prestazioni tramite la mancanza di capacità di utilizzare indici nel codice eseguito. Più in dettaglio: https://docs.mongodb.com/manual/reference/operator/query/where/#considerations

Inoltre, se si desidera controllare per gli array non vuoti specifico, utilizzare questo:

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

Tecnicamente, questo è anche meglio di quello attuale risposta del corrispondente $ esiste soluzione, dato che il campo può avere un oggetto non-array con un campo chiamato "0", e che corrisponderebbe a un "array non vuoto", che in questo caso è sbagliato.

Problemi correlati