Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongo $concatArrays even when null

Tags:

mongodb

I have a large set of documents that may have two arrays or one of the two. I want to merge them in a $project.

I am currently using $concatArrays but as the documentation says it returns null when one of the arrays is null. I can figure out how to add a condition statement in there that will either return the $concatArrays or what ever array is in there.

Example

I have:

{_id: 1, array1: ['a', 'b', 'b'], array2: ['e', 'e']}
{_id: 2, array1: ['a', 'b', 'b']}
{_id: 3, array2: ['e', 'e']}

I want:

{_id: 1, combinedArray: ['a','b', 'b', 'e', 'e']}
{_id: 2, combinedArray: ['a','b', 'b']}
{_id: 3, combinedArray: ['e', 'e']}

I tried:

 $project: {
   combinedArray: { '$concatArrays': [ '$array1', '$array2' ] }
 }

 //output (unexpected result): 
    {_id: 1, combinedArray: ['a','b', 'b', 'e', 'e']}
    {_id: 2, combinedArray: null}
    {_id: 3, combinedArray: null}

I also tried:

 $project: {
      combinedArray: { '$setUnion': [ '$array1', '$array2' ] }
 }
 //output (unexpected result): 
     {_id: 1, combinedArray: ['a','b', 'e']}
     {_id: 2, combinedArray: ['a','b']}
     {_id: 3, combinedArray: ['e']}
like image 524
Mika Avatar asked Feb 14 '17 11:02

Mika


2 Answers

As documentation for $concatArrays says

If any argument resolves to a value of null or refers to a field that is missing, $concatArrays returns null.

So we need to be sure that we are not passing arguments which refer to a missing field or null. You can do that with $ifNull operator:

Evaluates an expression and returns the value of the expression if the expression evaluates to a non-null value. If the expression evaluates to a null value, including instances of undefined values or missing fields, returns the value of the replacement expression.

So just return empty array if filed expression will not evaluate to non-null value:

db.collection.aggregate([
    {$project: {
          combinedArray: { '$concatArrays': [ 
              {$ifNull: ['$array1', []]},
              {$ifNull: ['$array2', []]}
           ] }
       }
    }
])
like image 80
Sergey Berezovskiy Avatar answered Nov 16 '22 03:11

Sergey Berezovskiy


You can easily achieve this with the $ifNull operator:

db.arr.aggregate([
   {
      $project:{
         combinedArray:{
            $concatArrays:[
               {
                  $ifNull:[
                     "$array1",
                     []
                  ]
               },
               {
                  $ifNull:[
                     "$array2",
                     []
                  ]
               }
            ]
         }
      }
   }
])

output:

{ "_id" : 1, "combinedArray" : [ "a", "b", "b", "e", "e" ] }
{ "_id" : 2, "combinedArray" : [ "a", "b", "b" ] }
{ "_id" : 3, "combinedArray" : [ "e", "e" ] }
like image 36
felix Avatar answered Nov 16 '22 04:11

felix