I’m working on a project in nodejs using mongodb as my database. I’m trying to get rid of elements within my array that have dates before today. The problem that I’m having is that at most 5 elements are being deleted. I want all elements that meet this criteria to be deleted. Also, when I don’t have user.possible.pull(items._id) const result = await user.save()
all elements that meet this criteria are shown in my deletePossible
array. However, when I do have user.possible.pull(items._id) const result = await user.save()
at most 5 are being shown as well.
In my database, my User document looks like:
_id: '',
name: '',
possible: Array
0 Object
date: "Tues Jan 10 2023",
_id: "63c0b169b6fa12ac49874a13"
1 Object
date: "Wed Jan 11 2023",
_id: "63c0b172b6fa12ac49874a32"
...
My code:
const user = await User.findById(args.userId)
const deletePossible = [];
for (var items of user.possible) {
if (+new Date(items.date) < +new Date().setHours) {
deletePossible.push(items._id)
user.possible.pull(items._id)
const result = await user.save()
}
}
`
console.log(deletePossible)
I’ve tried a number of things such as:
for (var item of deletePossible) {
user.possible.pull(item)
const result = await user.save()
}
following deletePossible.push(items._id)
, and
const userInfo = await User.updateOne( { _id: args.userId}, {possible:{$pull:[...deletePossible] }} )
which removes all of the arrays from possible
regardless of if it’s contained within deletePossible
and then adds a random _id
. Nothing I have tried seems to work. Does anyone have any idea why this is happening and how to get this to work properly? I would really appreciate any help or advice. Thank you!
2
Answers
You can simply
filter
user.possible
andsave
the updatedUser
:The core of the issue appears to not be related to Mongo or Mongoose really, but is rather just a standard algorithmic logic problem.
Consider the following code, which iterates over an array, logs each element, and removes the third element when it arrives at it:
This code outputs:
Notice anything interesting? 3 has been skipped.
This happens because deleting an element from an array causes everything in front of it to move up a position. So if you’re looking at 2 and you delete it, then 3 moves into 2’s place, and 4 moves into 3’s place. So then if you look at the next position, you’re now looking at 4, not 3. The code never sees the 3.
This is why you should never change an array while iterating over it. A lot of languages won’t even allow you to (if you’re using iterators), they’ll throw some sort of "underlying collection was modified during iteration" error. You can make it work if you know what you’re doing (often just by iterating over the array backwards), but there are usually better solutions anyway, like using
Array.prototype.filter()
.One easy solution is to iterate over a copy of the array, so that when you do the delete, the array you’re iterating over (the copy) isn’t changed. That would look like this:
Another problem with your code:
+new Date().setHours
will always evaluate toNaN
sincesetHours
is a function and converting a function to a number always results inNaN
. I suspect this is just a typo you introduced while struggling with the original issue.The suggestion to use
filter()
is even better.