2015-03-15 13 views
5

$ push è l'aggregazione di null se il campo non è presente. Vorrei evitare questo.

Esiste un modo per rendere un'espressione secondaria per $ push operator in modo tale che i valori nulli vengano saltati e non inseriti nell'array risultante?

risposta

4

Non è del tutto chiaro quale sia il caso specifico senza un esempio. C'è l'operatore $ifNull che può "sostituire" un valore nullo o un campo mancante con "qualcos'altro", ma non è possibile "saltare" veramente.

Detto questo, è sempre possibile "filtrare" i risultati in base al proprio caso d'uso effettivo.

Se i dati risultante è in realtà un "Set" e si dispone di una versione MongoDB che è 2.6 o superiore, allora è possibile utilizzare $setDifference con qualche aiuto da $addToSet per ridurre il numero di null valori che sono tenuti inizialmente:

db.collection.aggregate([ 
    { "$group": { 
     "_id": "$key", 
     "list": { "$addToSet": "$field" } 
    }}, 
    { "$project": { 
     "list": { "$setDifference": [ "$list", [null] ] } 
    }} 
]) 

Quindi ci sarebbe solo uno null e quindi l'operazione $setDifference lo "filtrerà" nel confronto.

Nelle versioni precedenti o quando i valori non sono in realtà "unica" e non un "set", allora "filtro" per l'elaborazione con $unwind e $match:

db.collection.aggregate([ 
    { "$group": { 
     "_id": "$key", 
     "list": { "$push": "$field" } 
    }}, 
    { "$unwind": "$list" }, 
    { "$match": { "list": { "$ne": null } }}, 
    { "$group": { 
     "_id": "$_id", 
     "list": { "$push": "$list" } 
    }} 
]) 

Se non si desidera di essere "distruttiva" di array, che finirebbero per "vuoto" perché contenevano "nient'altro che" null, poi si mantiene un uso conteggio $ifNull e corrispondenza delle condizioni:

db.collection.aggregate([ 
    { "$group": { 
     "_id": "$key", 
     "list": { "$push": "$field" }, 
     "count": { 
      "$sum": { 
       "$cond": [ 
        { "$eq": { "$ifNull": [ "$field", null ] }, null }, 
        0, 
        1 
       ] 
      } 
     } 
    }}, 
    { "$unwind": "$list" }, 
    { "$match": { 
     "$or": [ 
      { "list": { "$ne": null } }, 
      { "count": 0 } 
     ] 
    }}, 
    { "$group": { 
     "_id": "$_id", 
     "list": { "$push": "$list" } 
    }}, 
    { "$project": { 
     "list": { 
      "$cond": [ 
       { "$eq": [ "$count", 0 ] }, 
       { "$const": [] }, 
       "$list" 
      ] 
     } 
    }} 
]) 

Con un finale $project sostituzione di qualsiasi array che consisteva semplicemente di valori null solo con un oggetto array vuoto.

+0

Mi hai appena salvato dal crollo del cervello! grazie – mhlavacka

4

po 'tardi per il partito, ma ..

ho voluto fare la stessa cosa, e ha scoperto che ho potuto realizzare con un'espressione così:

// Pushes events only if they have the value 'A' 
    "events": { 
    "$push": { 
     "$cond": [ 
     { 
      "$eq": [ 
      "$event", 
      "A" 
      ] 
     }, 
     "A", 
     "$noval" 
     ] 
    } 
    } 

L'idea qui è che quando lo fai

{ "$push": "$event" } 

quindi sembra solo spingere valori non nulli.

Quindi ho creato una colonna che non esiste, $ noval, da restituire come condizione falsa del mio $ cond.

Sembra funzionare. Non sono sicuro se non è standard e quindi suscettibile di rompere un giorno, ma ..

+0

Funziona, ma non può essere utilizzato con gli indici e useremo sempre 'collscan' per vedere se esiste il valore inesistente. – Redsandro

+0

Ho lavorato nel mio caso, grazie. Mi hai salvato un sacco di tempo. – Kostanos

Problemi correlati