2011-05-22 12 views
15

Ho una collezione di messaggi:C'è un modo per aggiornare atomicamente due raccolte in MongoDB?

{ 
    messageid: ObjectId 
    userid: ObjectId 
    message: string 
    isread: true|false 
} 

e una collezione di messaggio che conta per utente:

{ 
    userid: ObjectId 
    total: int 
    unread: int 
} 

Quando si elimina un messaggio da "messaggi" di raccolta, ho anche bisogno di diminuire il "totale "in" conta "insieme, e condizionatamente (se" messages.isread "== false) diminuisce anche il campo" non letto ".

Per questo ho bisogno di recuperare prima il messaggio, controllare il suo campo "da leggere" e quindi aggiornare i conteggi. Esiste la possibilità che il messaggio venga contrassegnato come letto tra quelle azioni, quindi diminuirò i conteggi "non letti" in modo errato.

C'è un modo per modificare in modo condizionale qualcosa in una raccolta basata sui risultati di un'altra raccolta in un solo scatto?

risposta

11

Ci sono un sacco di risposte qui, ma voglio riempire tutti gli spazi vuoti qui:

C'è un modo per atomicamente aggiorna due raccolte in MongoDB?

No. L'aggiornamento atomico di due raccolte è effettivamente una transazione. MongoDB non supporta le transazioni tra collezioni o persino all'interno di una collezione.

MongoDB fornisce several modifiers che sono atomici su un singolo documento.In questo modo è possibile incrementare più variabili diverse contemporaneamente ($inc). Anche se qui ci sono alcune limitazioni, non è possibile eseguire due diverse operazioni su una singola proprietà.

C'è un modo per modificare in modo condizionale qualcosa in una raccolta basata sui risultati di un'altra raccolta in un solo scatto?

Ci sono alcuni documenti qui su atomic updates in generale. Tuttavia, ciò di cui hai veramente bisogno è una coda e qualche forma di two-phase commit o hai bisogno di trigger.

I trigger hanno not yet been implemented, quindi non è davvero un'opzione nel tuo caso.

C'è una possibilità che il messaggio venga contrassegnato come letto tra quelle azioni, quindi diminuirò i conteggi "non letti" in modo errato.

A questo punto, si dispone di un paio di strategie diverse per rendere questo comportamento con un certo livello di coerenza. Francamente, sulla base della tua descrizione, potresti voler indagare sulla creazione di una semplice coda che aggiorna i tuoi totali.

0

Si può fare questo con trigger in sql. Ma in Mongo non c'è un grilletto.

È possibile eseguire l'operazione su uno dei documento e verificare la presenza di LastErrorMessage su tale operazione impostando SafeMode.True

Poi, se nessun errore quindi aggiornare la seconda raccolta.

Attualmente non c'è modo di farlo in modo atomico.

Se c'è, l'avrei usato nel mio progetto. Anch'io avevo bisogno di quella funzionalità.

1

No, sfortunatamente questo non è possibile. MongoDB supporta solo atomic operations nell'ambito di un singolo documento. Non c'è modo di eseguire un'operazione transazionale su più documenti, anche se si trovano nella stessa collezione.

4

Non è possibile rimuovere documenti da due raccolte nello stesso istante. Quello che puoi fare è usare findAndModify() per rimuovere un documento in modo da ottenere il suo stato esatto prima che fosse cancellato. Questo si prenderà cura del tuo problema di conteggio non letto.

1

MongoDB è molto veloce, quindi se il tuo sito non è a carico elevato puoi semplicemente ricalcolare il numero totale di messaggi e il numero totale di messaggi letti su ogni richiesta. Metti solo un indice su isread. Count sembra essere molto veloce, anche su un grande volume di dati.

Infatti, i campi totali e non letti sono semplicemente cache. Ne hai davvero bisogno?

C'è una domanda su un problema simile qui: MongoDB: Calling Count() vs tracking counts in a collection

+0

Era anche la mia domanda :) Il mio sito sarà relativamente carico elevato, e non voglio ricalcolare le statistiche ogni volta che ho bisogno di loro, quindi sto usando quella raccolta contatore. – Andrey

+0

Dovresti profilarlo se non lo hai già fatto. – Maxence

+0

Anche senza profiling, posso dire che cursor.count() sarà sempre molto più lento del semplice recupero di un numero, specialmente su set con centinaia di milioni di record. – Andrey

Problemi correlati