Skip to content

MONGOID-5972 Avoid merging conflicting touch paths into embedded inserts - #6172

Draft
jamis wants to merge 1 commit into
mongodb:masterfrom
jamis:5972-embeds-many
Draft

jamis wants to merge 1 commit into
mongodb:masterfrom
jamis:5972-embeds-many

Conversation

@jamis

@jamis jamis commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

MONGOID-5972: Inserting an embeds_many child while another child of the same array has a pending touch update raises Mongo::Error::OperationFailure [40].

Description

Fixes a regression introduced by MONGOID-5867 (Merge touch updates into embedded document insert). insert_as_embedded merged the parent's pending touch updates into the same update_one that performed the embedded insert. For embeds_many, the insert produces $push on the array while a dirty sibling can make the touches include a path inside that array (e.g. items.0.updated_at). MongoDB rejects a single update whose operators target both a path and one of its ancestors or descendants, so the write failed with error 40. Before 9.1.0 the touch was persisted in its own update_one and the two never shared an update document.

The merge is now skipped when any touch path conflicts (equal, ancestor, or descendant) with a path the insert already targets. Such touches are deferred to the after_save callback's separate round-trip, matching pre-9.1 behavior. The single-round-trip optimization in MONGOID-5867 is preserved for the common case.

Verification

  • Added a regression context under describe 'touch merged with embedded insert' in spec/mongoid/touchable_spec.rb (the embedded push/create touch-merge coverage). It fails on master with error 40 and passes with the fix.
  • Touchable suite: 245 examples, 0 failures.
  • Persistable suite: 881 examples, 0 failures.
  • Creatable + touchable suites: 315 examples, 0 failures.
  • Timestamps, atomic, and embedded-association suites: 1584 examples, 0 failures.

@jamis
jamis requested a review from a team as a code owner September 11, 2026 21:48
@jamis
jamis requested review from JamesKovacs and a lite review from Copilot September 11, 2026 21:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two moderate review comments remain unresolved in the regression spec.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Fixes MongoDB path conflicts when inserting an embeds_many child alongside pending touch updates.

Changes:

  • Detects conflicting touch paths before merging updates.
  • Defers conflicting touches to the callback round-trip.
  • Adds regression coverage for MONGOID-5972.
File summaries
File Summary Review comments
spec/mongoid/persistable/creatable_5972_spec.rb Adds regression coverage for sibling insertion and touch persistence. Moderate (2 votes): deregister dynamically defined models during teardown. Moderate (1 vote): assert the sibling’s updated_at after reload.
lib/mongoid/persistable/creatable.rb Adds equal, ancestor, and descendant touch-path conflict detection. No comments.
Review details

Suppressed comments (1)

spec/mongoid/persistable/creatable_5972_spec.rb:59

  • Could this regression test also assert the first item's updated_at after reload? The new branch deliberately skips merging the $set, so the key behavior is that the after-save fallback still persists the touch; the current qty/archived assertions would pass even if that deferred touch were lost.
    it 'persists the updated first item' do
      first = parent.reload.m5972_items.first
      expect(first.qty).to eq(2)
      expect(first.archived).to be(false)
    end
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread spec/mongoid/persistable/creatable_5972_spec.rb Outdated
Inserting an embeds_many child while a sibling had a pending touch update
merged items.0.updated_at into the same $push update_one, which MongoDB
rejected with error 40. Skip the touch merge when a touch path would
conflict with a path the insert targets, deferring the touches to the
after_save callback's separate round-trip.
@jamis
jamis requested review from comandeo-mongo and removed request for JamesKovacs September 11, 2026 21:58
@jamis
jamis marked this pull request as draft September 11, 2026 22:26
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.

2 participants