My question is a combination of:
This question: Removing the array element in mongoDB based on the position of element
And this question: mongodb set object where key value dynamically changes
I know you can define the field (array) dynamically like this:
{ [arrayName]: { <condition> } }
But, I then want to remove a certain element in a dynamically defined array by specifying the position (which is also defined dynamically). In other words, the function that processes this query is coming in which two parameters: the array's name and the index of the element to remove.
The options given by the selected answer were the following:
Option 1, does not work (in general), adapted to my case this looks like:
{ $pull : { [arrayName] : { $gt: index-1, $lt: index 1 } } }
Option 2, I cannot use dynamically defined values in field selectors with quotation marks (as far as I am aware):
{ $pull : "[arrayName].[index]" }
or
{ $pull : "[arrayName].$": index }
Option 3, is different method but can't use it for the same reason:
{ $unset: { "[arrayName].[index]": 1 } } // Won't work
{ $pull: { [arrayName]: null } } // Would probably work
The only workarounds I can think of right now involve significantly changing the design which would be a shame. Any help is appreciated!
PS: I'm using mongoose as a driver on the latest version as of today (v6.3.5) and MongoDB version 5.0.8
CodePudding user response:
On Mongo version 4.2 You can use pipelined updates to achieve this, you can get it done in multiple ways, here is what I consider the easiest two ways:
- using
$slice
and$concatArrays
to remove a certain element:
db.collection.update({},
[
{
$set: {
[arrayName]: {
$concatArrays: [
{
$slice: [
`$${arrayName}`,
index,
]
},
{
$slice: [
`$${arrayName}`,
index 1,
{
$size: `$${arrayName}`
}
]
}
]
}
}
}
])
- using
$filter
and$zip
to filter out based on index:
db.collection.updateOne(
{},
[
{
"$set": {
[arrayName]: {
$map: {
input: {
$filter: {
input: {
$zip: {
inputs: [
{
$range: [
0,
{
$size: `$${arrayName}`
}
]
},
`$${arrayName}`
]
}
},
cond: {
$ne: [
{
"$arrayElemAt": [
"$$this",
0
]
},
index
]
}
}
},
in: {
$arrayElemAt: [
"$$this",
1
]
}
}
}
}
}
])
Alternatively you can just prepare