I have an array that is like [1,2,1,2,3,5,2]. And I want to remove only one element amongst the selected elements. I used $pull operator and it doesn't work as I required, it remove all elements I specified.
db.user.updateOne({_id: ...}, {$pull:{'array': 1}})
I tried it and give this result: [2,2,3,5,2].
is there any way to get the result: [2,1,2,3,5,2]
CodePudding user response:
This feature does not exist (and won't), as you can see in this Jira. ticket they choose they won't do this.
Here is a hacky work around - the strategy will be to find the index of the first matching element and slice it out of the array, like so:
db.collection.update({},
[
{
"$set": {
"array": {
"$concatArrays": [
{
$cond: [
{
$gt: [
{
"$indexOfArray": [
"$array",
1
]
},
0
]
},
{
"$slice": [
"$array",
0,
{
"$indexOfArray": [
"$array",
1
]
}
]
},
[]
]
},
{
"$slice": [
"$array",
{
"$add": [
{
"$indexOfArray": [
"$array",
1
]
},
1
]
},
{
"$size": "$array"
}
]
}
]
}
}
}
])
CodePudding user response:
Query
- $reduce the array starting with
{"n-ar": [], "found": false}
- the first time you find it you ignore it, and you set
found=true
- else you just
$concat
to add the member to the new-ar
*it can be generalized, like remove the first 4 occurences, if integer is used as found
aggregate(
[{"$set":
{"ar":
{"$getField":
{"field": "n-ar",
"input":
{"$reduce":
{"input": "$ar",
"initialValue": {"n-ar": [], "found": false},
"in":
{"$cond":
[{"$and":
[{"$eq": ["$$this", 1]}, {"$eq": ["$$value.found", false]}]},
{"n-ar": "$$value.n-ar", "found": true},
{"n-ar": {"$concatArrays": ["$$value.n-ar", ["$$this"]]},
"found": "$$value.found"}]}}}}}}}])