How to convert an array of array to an array of single value with updateMany()?

Hi,

I have an array that should contain only single value.
An error occured and a few elements are “arrays”, for example :

"barcodes": ["1129118150100", "3606234836070", ["1129118150100150", "1129118150100151"]]

I want to correct the mistakes using find() method to get this result :

"barcodes": ["1129118150100", "3606234836070", "1129118150100150", "1129118150100151"]

The filter is right, I’m trying to code an aggregation pipeline with $set but don’t succeed.

{
  $expr: {
    $gt: [
      {$reduce:
        {
          input:'$barcodes',
          initialValue:0,
          in:{
            $add:['$$value',{$cond:[{$eq:[{$type:'$$this'},'array']},1,0]}]
          }
        }
      },
      0
    ]
  }   
}

Do you think there is a solution ?

You were on the right track with $reduce. The enclosing $expr and $gt were not. The $add was not the correct operator. Try:

{ "$set" : {
  "barcodes" :
  {
    "$reduce" :
    {
       "input" : "$barcodes" ,
       "initialValue" : [] ,
       "in" : { "$concatArrays" : [
           "$$value' ,
           { "$cond" : [
             { "$eq" : [ {"$type" : "$$this"} , "array" ] } ,
             "$$this" ,
             [ "$$this" ]
           ] }
       ] }
    }
  }
} }

In migration scenarios like yours, what I like to do is to migrate $out into a temporary collection, which I can verify before $merge-ing it back to the real collection. But you need downtime because between the $out and $merge, original data may change.

You may replace

with the short-cut

{ "$isArray" : "$$this" }

Hi Steeve,

Thanks for your answer.
I also need a filter to find the errors = barcodes array with elements of type “array”

"barcodes": ["1129118150100", "3606234836070", ["1129118150100150", "1129118150100151"]]

So here is my filter :

{
  $expr: {
    $gt: [
      {$reduce:
        {
          input:'$barcodes',
          initialValue:0,
          in:{
            $add:['$$value',{$cond:[{$eq:[{$type:'$$this'},'array']},1,0]}]
          }
        }
      },
      0
    ]
  }   
}

I use “$reduce”, but I’m asking how to get the same result with a simple way ?
I tried 'barcodes.$':{$type: 'array' } to check if an element of the array is an array, but this syntax is wrong

I have done anything for the filter because in your first post you wrote

The following should work:

{ "barcodes" : { $elemMatch : { "$type" : "array" }}}

I have updated the collection with updateMany() operator

db.barcodes.updateMany(
{
    barcodes:{$elemMatch:{$type:'array'}}
},
{
    $set: {
       barcodes : {
            $reduce : {
                input : '$barcodes' ,
                initialValue : [] ,
                in: { '$concatArrays' : [
                    '$$value' ,
                    { $cond : [
                        { "$isArray" : "$$this" } ,
                        '$$this' ,
                        [ '$$this' ]
                    ] }
                ] }
            }
        }
    }
}
)

The result is wrong, I got the string value of the operator but not the value

{
  _id: 'fr_150371',
  barcodes: {
    '$reduce': {
      input: '$barcodes',
      initialValue: [],
      in: {
        '$concatArrays': [ '$$value', { '$cond': [ [Object], '$$this', [Array] ] } ]
      }
    }
  }
}

Don’t understand where is the error ?

To update with aggregation, you need to put your $set into [ ].

I forgot [ ] to open and close the pipeline !
Now it’s OK

db.barcodes.updateMany(
{
    barcodes:{$elemMatch:{$type:'array'}}
},
[
{
    $set: {
       barcodes : {
            $reduce : {
                input : '$barcodes' ,
                initialValue : [] ,
                in: { '$concatArrays' : [
                    '$$value' ,
                    { $cond : [
                        { '$isArray' : '$$this' } ,
                        '$$this' ,
                        [ '$$this' ]
                    ] }
                ] }
            }
        }
    }
}
]
)
2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.