How to avoid $ push-ing nulls in mongo aggregation structure

$ push - aggregation of zeros if the field is absent. I would like to avoid this.

Is there a way to make a subexpression for the $ push operator so that null values ​​are skipped and not placed in the resulting array?

+5
source share
2 answers

In fact, it is not entirely clear what your specific case is without an example. There is a $ifNull that can “replace” a null value or an absent “something else” field, but it is impossible to truly “skip” it.

However, you can always “filter” the results depending on your actual use.

If your resulting data is actually “Set” and you have a version of MongoDB that is 2.6 or higher, you can use $setDifference with $addToSet to reduce the number of null values ​​that are stored initially:

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

That way, there will be only one null , and then the $setDifference operation will "filter" this by comparison.

In earlier versions, or when the values ​​are not "unique" and not "set", then you "filter" by processing with $unwind and $match :

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

If you do not want to be "destructive" of arrays that end in "empty" because they contain "nothing but" null , then you keep using count $ifNull and match the conditions:

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

With the final $project replacing any array that simply consisted of null values ​​with only an empty array object.

+4
source

Beat was late for the party, but ..

I wanted to do the same and found that I can accomplish this with the following expression:

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

The thought here is that when you do

 { "$push": "$event" } 

then it seems to only push nonzero values.

So, I made up a column that does not exist, $ noval, which will be returned as a false condition of my $ cond.

It seems to have worked. I’m not sure that it is non-standard and therefore prone to hacking in one day, but ..

+4
source

Source: https://habr.com/ru/post/1215403/


All Articles