2010-08-12 7 views
6

So che questa domanda è stata fatta prima, ma quello è uno scenario diverso. Mi piacerebbe avere una collezione come questa:C'è un modo per spostare un elenco con una singola query?

{ 
    "_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
    "pk": 1, 
    "forums": [{ 
     "pk": 1, 
     "thread_count": 10, 
     "post_count": 20, 
    }, { 
     "pk": 2, 
     "thread_count": 5, 
     "post_count": 24, 
    }] 
} 

Quello che voglio fare è quello di upsert un elemento di "forum", incrementando contatori o l'aggiunta di un elemento se non esiste.

Ad esempio, per fare qualcosa di simile (spero abbia senso):

db.mycollection.update({ 
    "pk": 3, 
    "forums.pk": 2 
}, { 
    "$inc": {"forums.$.thread_count": 1}, 
    "$inc": {"forums.$.post_count": 1}, 
}, true) 

e avere:

{ 
    "_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
    "pk": 1, 
    "forums": [{ 
     "pk": 1, 
     "thread_count": 10, 
     "post_count": 20, 
    }, { 
     "pk": 2, 
     "thread_count": 5, 
     "post_count": 24, 
    }] 
}, 
{ 
    "_id" : ObjectId("4c28f62cbf8544c60506f11e"), 
    "pk": 3, 
    "forums": [{ 
     "pk": 2, 
     "thread_count": 1, 
     "post_count": 1, 
    }] 
} 

posso sicuramente farlo in tre fasi:

  1. Upsert l'intera raccolta con un nuovo articolo
  2. addToSet l'elemento del forum alla lista
  3. contatori
  4. incremento voce forum con operatore posizionale

Vale a dire:

db.mycollection.update({pk:3}, {pk:3}, true) 
db.mycollection.update({pk:3}, {$addToSet: {forums: {pk:2}}}) 
db.mycollection.update({pk:3, 'forums.pk': 2}, {$inc: {'forums.$.thread_counter': 1, {'forums.$.post_counter': 1}}) 

Sei a conoscenza di un modo più efficiente per farlo? TIA, Germano

risposta

10

Come avrete scoperto, il positional operator non può essere utilizzato in upserts:

L'operatore di posizione non può essere combinato con un upsert in quanto richiede un elemento di un array di corrispondenza. Se il tuo aggiornamento produce un inserto, il "$" sarà letteralmente usato come nome del campo.

Quindi non sarà possibile ottenere il risultato desiderato in una singola query.

È separare la creazione del documento dal contatore di aggiornamento. La tua soluzione è sulla strada giusta. Può essere condensato nelle seguenti due domande:

// optionally create the document, including the array 
db.mycollection.update({pk:3}, {$addToSet: {forums: {pk:2}}}, true) 

// update the counters in the array item 
db.mycollection.update({pk:3, 'forums.pk': 2}, {$inc: {'forums.$.thread_counter': 1, 'forums.$.post_counter': 1}}) 
+0

Sì, l'ho capito. Grazie comunque. – Germano

Problemi correlati