2011-02-11 20 views
19

Ho una domanda qui sotto. Voglio ottenere elementi tra 4 e 6, quindi solo a: 1 deve corrispondere perché ha il valore 5 in b.

> db.test.find({ b : { $gt : 4 }, b: {$lt : 6}}); 
{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 3, 4, 5 ] } 
{ "_id" : ObjectId("4d54d0074364000000004332"), "a" : 2, "b" : [ 2, 4, 6, 8 ] } 
> 

Qualcuno può dire perché a: 2 corrisponde a questa query? Non riesco davvero a capire perché viene restituito.

Ho provato anche quello che è stato specificato nel tutorial, ma id non sembra funzionare:

> db.test.find({ b : { $gt : 4, $lt : 6}}); 
{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 3, 4, 5 ] } 
{ "_id" : ObjectId("4d54d0074364000000004332"), "a" : 2, "b" : [ 2, 4, 6, 8 ] } 
> 

E questo per evitare qualsiasi confusione per quanto riguarda GT/GTE

> db.test.find({b: {$gt: 4.5, $lt: 5.5}}); 
{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 3, 4, 5 ] } 
{ "_id" : ObjectId("4d54d0074364000000004332"), "a" : 2, "b" : [ 2, 4, 6, 8 ] } 
> 

solo: 1 dovrebbe essere restituito.

Come suggerito, ho dato $ elemMatch una prova, ma non sembra lavorare sia (objectIds sono diverse perché io sono su una macchina diversa)

> db.test.find(); 
{ "_id" : ObjectId("4d5a24a5e82e00000000433f"), "a" : 1, "b" : [ 2, 3, 4, 5 ] } 
{ "_id" : ObjectId("4d5a24bbe82e000000004340"), "a" : 2, "b" : [ 2, 4, 6, 8 ] } 
> db.test.find({b: {$elemMatch: {$gt : 4, $lt: 6 }}}); 
> 

Nessun documento sono stati restituiti.

+0

In realtà, entrambi i documenti devono essere restituiti, la questione significa "dammi tutti i documenti in cui' B' ha un valore compreso tra 4 e 6", e questo è soddisfatto da entrambi i documenti. Potresti spiegare più in dettaglio a cosa si desidera richiedere? Perché dovrebbe essere trovato il primo documento ma non il secondo? – Theo

+0

Come dici sopra, voglio tutti i documenti che hanno ab tra 4 e 6. Solo a: 1 soddisfa questo (non entrambi) perché a: 2 non contiene alcun valore tra 4 e 6 (usando gt e lt escludi 4 e 6 loro stessi dove li includerebbe gte e lte). Ho provato una query diversa (vedi la domanda modificata) che è più chiara e non funziona ancora correttamente ... – paullb

+1

Vedo cosa intendi ora, ci ho pensato come un intervallo (e gli intervalli di solito includono il primo elemento) , ma ovviamente non lo è, è un rigore minore e più grande di. Ho cancellato la mia risposta dal momento che ora è chiaro che era sbagliato. – Theo

risposta

51

Questo è un argomento davvero confuso. Lavoro a 10gen e ho dovuto passare un po 'di tempo a girargli intorno;)

Esaminiamo in che modo il motore di query elabora questa query.

Ecco la domanda di nuovo:

> db.test.find({ b : { $gt : 4, $lt : 6}}); 

Quando si arriva al record che sembra che non dovrebbe corrispondere ...

{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 4, 6, 8 ] } 

La partita non viene eseguita contro ogni elemento del array, ma piuttosto contro l'array nel suo complesso.

Il confronto viene eseguito in tre fasi:

Fase 1: Trova tutti i documenti in cui B ha un valore superiore a 4

B: [2,4,6,8] corrisponde perché 6 & 8 sono maggiori di 4

Fase 2: Trova tutti i documenti in cui B ha un valore inferiore a 6

B: [2,4,6,8] partita es perché 2 & 4 sono meno di 6

Fase 3: Trovare l'insieme dei documenti che ha trovato in entrambe punto 1 & 2.

Il documento con B: [2,4,6,8] corrisponde a entrambi i passaggi 1 & 2 quindi viene restituito come corrispondenza. Tieni presente che i risultati vengono anche deduplicati in questo passaggio, quindi lo stesso documento non verrà restituito due volte.

Se si desidera applicare la query ai singoli elementi dell'array anziché all'intero array, è possibile utilizzare l'operatore $ elemMatch. Ad esempio

> db.temp.find({b: {$elemMatch: {$gt: 4, $lt: 5}}}) 
> db.temp.find({b: {$elemMatch: {$gte: 4, $lt: 5}}}) 
    { "_id" : ObjectId("4d558b6f4f0b1e2141b66660"), "b" : [ 2, 3, 4, 5, 6 ] } 
+0

Grazie, Jared, per la risposta ben strutturata. Tuttavia, dopo averlo provato, non sembra funzionare. (Ho provato "db.test.find ({b: {$ elemMatch: {$ gt: 4, $ lt: 6}}});" come hai descritto. (Vedi la domanda modificata per i dettagli) Puoi far luce su questo? – paullb

+0

Strano. Funziona per me. > db.array2.save ({b: [2,3,4,5]}) > db.array2.save ({b: [2,4, 6,8]}) > db.array2.find ({b: {$ elemMatch: {$ gt: 4, $ lt: 6}}}) {"_id": ObjectId ("4d5a9268ec5855af36625ed6"), "b ": [2, 3, 4, 5]} > Quale versione di MongoDB stai usando? $ ElemMatch è stato aggiunto 1.3.1, quindi se stai ancora usando 1.2 non funzionerà. – jared

+0

Non funziona lavoro qui. Ho appena copiato e incollato le tue query (inserisci e poi esegui una query) .Io 1.6.5. Sembra che potrebbe essere un bug: http://jira.mongodb.org/browse/SERVER-1264 – paullb

-9

Perché non è stata verificata la documentazione.

Vedi

http://www.mongodb.org/display/DOCS/Advanced+Queries

e controllo per "gamme" nella pagina.

Né è la sintassi di query corretta (confrontare con l'esempio)

né il vostro "perché una: 2" parte della domanda ha alcun senso dal momento che 'a' non è coinvolto nella query. Se si desidera cercare un: 1, è necessario includerlo nella query.

Tenere presente che tutte le clausole di query sono AND combinate per impostazione predefinita a meno che non si utilizzi $ o l'operatore.

+0

Inoltre: se sei interessato a un sottoinsieme di campi: http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields –

+0

Grazie per aver indicato l'esempio di intervallo su quella pagina. Avevo visto la pagina ma ho perso la sezione della gamma. La sintassi è ovviamente corretta quando la query viene eseguita, ma non sto sfruttando il fattore di intervallo. Il "perché a: 2" ha perfettamente senso poiché identifica in modo univoco ogni riga, non deve essere coinvolto nella query. Devo anche sottolineare che se la clausola viene interpretata come AND, la mia query dovrebbe comunque prendere la gamma giusta. Quindi grazie per il link, ma no grazie per la scortesia generale. – paullb

+0

Maleducazione generale? Per favore guarda leggere il tutorial. –

0
.find({$and:[ {b:{$gt:4}}, {b:{$lt:6}} ]}) 
+3

No. La sintassi visualizzata nella risposta accettata è corretta ed è già un'operazione "e". Questo è puro e un cattivo esempio di sintassi leggibile. –

4

$ gt

Syntax: {field: {$gt: value} } 

es:

db.inventory.find({ qty: { $gt: 20 } }) 

$ lt

Syntax: {field: {$lt: value} } 

es:

db.inventory.find({ qty: { $lt: 20 } }) 

EG2:

db.inventory.find({ qty : { $gt : 20, $lt : 60}}); 
Problemi correlati