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 ?
steevej
(Steeve Juneau)
June 22, 2022, 1:23am
2
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.
steevej
(Steeve Juneau)
June 22, 2022, 1:28am
3
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
steevej
(Steeve Juneau)
June 23, 2022, 12:11pm
5
I have done anything for the filter because in your first post you wrote
emmanuel_bernard:
The filter is right
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 ?
steevej
(Steeve Juneau)
June 23, 2022, 2:35pm
7
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
system
(system)
Closed
June 28, 2022, 2:38pm
9
This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.