2015-10-05 11 views
5

Ho una collezione Mongo di messaggi che assomiglia a questo:Mongo sorta su una condizione calcolata

{ 
    'recipients': [], 
    'unRead': [], 
    'content': 'Text' 
} 

destinatari è un array di ID utente, e non letti è un array di tutti gli utenti che non hanno ancora aperto il Messaggio. Che sta lavorando come previsto, ma ho bisogno di interrogare l'elenco di tutti i messaggi in modo che restituisca i primi 20 risultati, dando priorità a quelli non letti prima, qualcosa di simile:

db.messages.find({recipients: {$elemMatch: userID} }) 
    .sort({unRead: {$elemMatch: userID}}) 
    .limit(20) 

Ma questo non funziona. Qual è il modo migliore per dare la priorità ai risultati in base al fatto che soddisfino determinati criteri?

risposta

5

se si vuole "peso" i risultati in base a determinati criteri o hanno alcun tipo di "valore calcolato" all'interno di una "sorta", allora avete bisogno il metodo .aggregate() invece. Questo permette di "proiettata" valori da utilizzare nell'operazione $sort, per cui solo un campo presente nel documento può essere utilizzato:

db.messages.aggregate([ 
    { "$match": { "messages": userId } }, 
    { "$project": { 
     "recipients": 1, 
     "unread": 1, 
     "content": 1, 
     "readYet": { 
      "$setIsSubset": [ [userId], "$unread" ] } 
     } 
    }}, 
    { "$sort": { "readYet": -1 } }, 
    { "$limit": 20 } 
]) 

Qui il confronto $setIsSubset operatore permette di matrice "leggere" con un allineamento convertito di [userId] per vedere se ci sono delle corrispondenze. Il risultato sarà true dove esiste l'ID utente o false dove non lo è.

Questo può quindi essere passato a $sort, che ordina i risultati con preferenza per le partite (decending sort è true in alto), e, infine, $limit solo restituisce i risultati fino alla quantità specificata.

Quindi, per utilizzare un termine calulato per "ordinare", il valore deve essere "proiettato" nel documento in modo che possa essere ordinato. Il quadro di aggregazione è come lo fai.

Si noti inoltre che $elemMatch non è richiesto solo per far corrispondere un singolo valore all'interno di un array e che è necessario specificare solo il valore direttamente. Lo scopo è dove devono essere soddisfatte le condizioni "multiple" su un singolo elemento dell'array, che ovviamente non si applica qui.

+0

Questo ha funzionato perfettamente. Grazie! L'unico commento che farò è che Mongo ha generato un errore fino a quando ho cambiato $ setIsSubSet su $ setIsSubset. – beatniknight

+0

@beatniknight Tipico me. Il collegamento alla documentazione era corretto ma il mio cervello di camelCase continua a dire che sono due parole e continua a digitarlo in quel modo. –