Conversation
MongooseArray#pull() finds matches with MongooseArray#indexOf(), which compares with `==`. Two Date objects are only `==` when they are the same instance, so pulling a date left it in the local array while the $pullAll still removed it on save. If the array was also pushed to before saving, the atomics fall back to $set and the pulled date was written back. addToSet() already compares dates by timestamp; do the same in indexOf(), which also makes includes() work for dates.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
pull()on a[Date]array does not remove the date from the document, even though the$pullAllit registers does remove it from the database.pull()looks for matches withthis.indexOf.call(values, mem), andMongooseArray#indexOf()compares with==. That works for numbers and strings, and ObjectIds are converted to strings first, but twoDateobjects are only==when they are the same instance. The value passed topull()is cast to a newDate, so it never matches.The local array and the database then disagree after
save(). It gets worse when the same array is also pushed to before saving:$pullAlland$pushcan't be combined, so the atomics fall back to$setof the local array, and the date that was pulled is written back.addToSet()already handles this case with its owndatebranch that compares+d === val, soaddToSet()andpull()currently disagree about whether two equal dates are the same value. This PR does the same timestamp comparison inindexOf().pull()andremove()pick it up through their existing call, andincludes()/indexOf()now find dates by value too, the same way they already find ObjectIds by value.Not changed here:
Decimal128,Double,UUIDandBufferarrays also compare by reference, in bothaddToSet()andpull(). Unlike dates, neither method has an equality rule for those types today, so that needs a per-type decision rather than making the two methods agree. Happy to follow up if you want that.Examples
Added two tests in
test/types.array.test.js: one underpull()that covers both the local array and the saved result afterpull()+push(), and one underindexOf()forindexOf()/includes()on dates, includingfromIndexand a Mixed array holding the same timestamp as a number (which must still not match aDate). Both fail onmasterand pass with this change.