2015-03-15 22 views
5

$ push agreguje wartości null, jeśli pole nie jest obecne. Chciałbym tego uniknąć.

Czy istnieje sposób na wyrażenie podrzędne dla operatora $ push w taki sposób, że wartości puste będą pomijane i niewprowadzane do wynikowej tablicy?

Odpowiedz

4

To naprawdę nie do końca jasne, jaki jest twój konkretny przypadek bez przykładu. Istnieje operator $ifNull, który może "zamienić" wartość pustą lub brakujące pole na "coś innego", ale naprawdę "pominięcie" nie jest możliwe.

Powiedziawszy, możesz zawsze "filtrować" wyniki w zależności od rzeczywistego przypadku użycia.

Jeśli uzyskane dane jest rzeczywiście „Set” i masz wersję MongoDB że 2.6 lub nowszej można użyć $setDifference z pewną pomocą $addToSet do zmniejszenia liczby null wartości, które są przechowywane na początku:

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

Tak więc będzie tylko jeden null, a następnie operacja $setDifference "odfiltruje" to w porównaniu.

We wcześniejszych wersjach lub gdy wartości nie są w rzeczywistości „wyjątkowy”, a nie „set”, a następnie „filtr” przez przetwarzanie z $unwind i $match:

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

Jeśli nie chcesz być „destrukcyjny” tablic, które kończą się „pusty”, ponieważ zawierały one „niczym” null, a następnie zachować użycie count $ifNull i mecz na następujących warunkach:

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" 
      ] 
     } 
    }} 
]) 

z końcowym $project zastępowanie dowolnej tablicy, która po prostu składała się z wartości tylko z pustym obiektem tablicy.

+0

Właśnie uratowałeś mnie od krachu mózgu! dzięki – mhlavacka

4

Bit późno do partii, ale ..

chciałem zrobić to samo, i okazało się, że mogę wykonać go z wyrazem jak ten:

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

Myślenie jest to, że kiedy robisz

wtedy wydaje się, że tylko wypychasz wartości inne niż null.

Więc wymyśliłem kolumnę, która nie istnieje, $ noval, która zostanie zwrócona jako fałszywy warunek mojego dolara.

Wydaje się działać. Nie jestem pewien, czy to jest niestandardowe, a zatem podatne na złamanie jednego dnia, ale ..

+0

To działa, ale nie może być używane z indeksami i zawsze będzie używać 'collscan', aby sprawdzić, czy istnieje nieistniejąca wartość. – Redsandro

+0

Pracowałem w moim przypadku, dziękuję. Uratowałeś mi dużo czasu. – Kostanos

Powiązane problemy