2011-07-07 9 views
27

Ho una collezione strutturata nel seguente modo:MongoDB: abbinare doc non vuoto in ordine di

{ 
    _id: 1, 
    score: [ 
    { 
     foo: 'a', 
     bar: 0, 
     user: {user1: 0, user2: 7} 
    } 
    ] 
} 

Ho bisogno di trovare tutti i documenti che hanno almeno un 'punteggio' (elemento in ordine di punteggio), che ha una certa valore di 'bar' e un sotto-documento 'utente' non vuoto.

Questo è quello che mi è venuta (e sembrava che dovrebbe funzionare):

db.col.find({score: {"$elemMatch": {bar:0, user: {"$not":{}} }}}) 

Ma, ottengo questo errore:

error: { "$err" : "$not cannot be empty", "code" : 13030 } 

Qualsiasi altro modo per fare questo?

+0

È esattamente * come è strutturato? Sembra un po 'fuori. **> var doc = {punteggio: [foo: 'a', barra: 0, utente: {utente1: 0, utente2: 7}]}; gio 7 luglio 00:43:42 SintassiErrore: mancante] dopo la lista di elementi (shell): 1 ** –

+0

@Justin: hai ragione, hai dimenticato le parentesi all'interno della matrice. – Dmitri

risposta

51

Calcolato: { 'score.user': { "$gt": {} } } corrisponderà a documenti non vuoti.

+0

In questo caso, 'score.user' è un oggetto. Funzionerebbe anche per verificare se 'score', un array, è vuoto? – zVictor

+4

Potrebbe, ma per gli array è meglio usare: '{foo: {$ not: {$ size: 0}}}' – Dmitri

+0

eccellente! Ho provato, ed entrambi hanno funzionato. Sai perché la seconda opzione sarebbe meglio? – zVictor

0

Controllare l'operatore $ size per verificare le dimensioni degli array.

+0

Non sto controllando la dimensione di alcun array. Ho lasciato fuori una serie di parentesi prima, potrebbe essere più chiaro ora. Un operatore equivalente per documenti/oggetti funzionerebbe, ma non sembra esistere. – Dmitri

3

Non sono sicuro di aver capito il tuo schema, ma forse il modo più semplice sarebbe di non avere un valore "vuoto" per score.user?

Invece di proposito non avere quel campo nel documento se non ha contenuto?

Allora la vostra richiesta potrebbe essere qualcosa di simile ...

> db.test.find({ "score" : { "$elemMatch" : { bar : 0, "user" : {"$exists": true }}}}) 

cioè alla ricerca di un valore in score.bar che si desidera (0 in questo caso) verificare l'esistenza mear ($ esiste, see docs) di score.user (e se ha un valore, allora verrà esistere?)

editied: oops ho perso il $ elemMatch avevi ...

+1

Sì, ho pensato di farlo in questo modo, il motivo principale per cui preferirei una query che corrisponda all'utente inesistente e vuoto 'è che i singoli punteggi degli utenti possono essere rimossi e preferirei non dover controllare se il subdoc è vuoto e deve essere rimosso ogni volta. – Dmitri

1

Probabilmente si desidera aggiungere un array ausiliario che tiene traccia degli utenti nel documento user:

{ 
    _id: 1, 
    score: [ 
    { 
     foo: 'a', 
     bar: 0, 
     users: ["user1", "user2"], 
     user: {user1: 0, user2: 7} 
    } 
    ] 
} 

Quindi è possibile aggiungere nuovi utenti atomicamente :

> db.test.update({_id: 1, score: { $elemMatch: {bar: 0}}},      
... {$set: {'score.$.user.user3': 10}, $addToSet: {'score.$.users': "user3"}}) 

rimuovere utenti:

> db.test.update({_id: 1, score: { $elemMatch: {bar: 0}}}, 
... {$unset: {'score.$.user.user3': 1}, $pop: {'score.$.users': "user3"}})  

punteggio Query s:

> db.test.find({_id: 1, score: {$elemMatch: {bar: 0, users: {$not: {$size: 0}}}}}) 

Se sai che dovrai essere l'aggiunta di solo gli utenti inesistenti e la rimozione di utenti esistenti dal documento user, è possibile semplificare users ad un contatore invece di un array, ma quanto sopra è più resistente.

Problemi correlati