Skip to content

fix(array): keep earlier pushed values when push() is called again with $each - #16619

Merged
vkarpov15 merged 1 commit into
Automattic:masterfrom
maxymlyskov:fix/keep-earlier-pushed-values-on-push-each
Nov 9, 2026
Merged

vkarpov15 merged 1 commit into
Automattic:masterfrom
maxymlyskov:fix/keep-earlier-pushed-values-on-push-each

Conversation

@maxymlyskov

Copy link
Copy Markdown
Contributor

Summary

Fixes #16618.

push(3) then push({ $each: [4] }) before a save sends only { $push: { nums: { $each: [4] } } }, so the 3 never reaches the database. _registerAtomic() replaces a pending $push whenever the new one has $each, and push() only falls back to $set for two different $position values (gh-14244). Same with two { $each } pushes. The other order breaks too: a plain push(3) after push({ $each: [0], $position: 0 }) joins the positioned $each and is saved at the front.

Now a second push() adds its values to the pending $each instead of replacing it. If either push has $position, $slice or $sort, the whole array is saved with $set, like the different $position case already is.

One catch: if a $push is already pending, a $slice or $sort on either push isn't sent, because the array is saved as the document holds it. A single push still sends them. I didn't touch a plain push() after a pending $push with $slice or $sort, it still joins that $push like on master.

Examples

const doc = await Test.create({ nums: [1, 2] });
doc.nums.push(3);
doc.nums.push({ $each: [4] });
await doc.save();
// before: db has [1, 2, 4]
// after: db has [1, 2, 3, 4]

const doc2 = await Test.create({ nums: [1, 2] });
doc2.nums.push({ $each: [0], $position: 0 });
doc2.nums.push(3);
await doc2.save();
// before: db has [0, 3, 1, 2]
// after: db has [0, 1, 2, 3], saved with $set
  • Ran: npx mocha test/types.array.test.js -g "gh-16618". The 3 new tests (one on a document array) fail on master and pass here. test/document.test.js still passes, different behavior of arrays in 6.x when compared to 5.x #14244 included.
  • Ran: npm run test:ci, 4677 passing, 47 pending, 0 failing.
  • npx eslint on the changed files is clean.

Node 22.23.3, MongoDB 8.2.6 (mongodb-memory-server), Linux.

…th $each

A second push() in the { $each } form replaced the pending $push, so save()
only wrote the last batch. Add its values to the pending $each instead, and
save the whole array with $set when either push has $position, $slice or
$sort, as push() already does for two different $position values (Automatticgh-14244).
A plain push() after a positioned one falls back to $set too.

Fix Automattic#16618
@vkarpov15 vkarpov15 added this to the 9.12.1 milestone Nov 9, 2026
@vkarpov15
vkarpov15 merged commit b9fbdbd into Automattic:master Nov 9, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A second push() with $each before save() drops the values of the earlier push() from the update

2 participants