Skip to content

Mongoose v8.13.1 Persistence Issues with Subdocuments and Specific Fields in Next.js/TypeScript Project #15347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
CoderNoveau opened this issue Apr 6, 2025 · 2 comments
Labels
needs clarification This issue doesn't have enough information to be actionable. Close after 14 days of inactivity

Comments

@CoderNoveau
Copy link

Prerequisites

  • I have written a descriptive issue title

Mongoose version

18.13.1

Node.js version

22.14.0

MongoDB version

8.0.6

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

No response

Issue

Summary:
We are experiencing persistent issues in a SaaS project using Mongoose (v8.13.1) where it fails to reliably save or retrieve certain data types, specifically embedded subdocument arrays and occasionally specific string fields, immediately after creation or update operations. This behavior is most pronounced in our Jest test environment using mongodb-memory-server (v10.1.4) but has also been observed for specific fields in the development environment (Dockerized MongoDB). Often, these failures are silent, with Mongoose methods (.save(), .create(), .findById(), .findByIdAndUpdate()) completing without error, but the data is not persisted or returned correctly in the subsequent read/document state. We have implemented several workarounds using the native MongoDB driver, but are seeking insights into the root cause or potential configuration fixes.

Project Context:

Application: A SaaS platform.
Stack:
Frontend/Backend: Next.js (v14.2.26) with API Routes
Language: TypeScript
ODM: Mongoose (v8.13.1)
Database: MongoDB (Docker container for dev, mongodb-memory-server v10.1.4 for tests)
Authentication: next-auth (v4.24.11)
Validation: zod (v3.24.2)
Testing: Jest (v29.7.0), ts-jest, next-test-api-route-handler (v4.0.16)
Detailed Description of Issues:

Subdocument Array Persistence Failure (Model A):

Scenario: Updating a primary model document's embedded array field (e.g., subdocumentArrayField) via a PUT /api/model-a/[id] endpoint.
Problem: Using Mongoose methods like doc.save() or ModelA.findByIdAndUpdate() appeared successful (no errors thrown, logs indicated updates), but the changes to the subdocumentArrayField array were not persisted in the database.
Model: Schema A contains subdocumentArrayField: [SubdocumentSchemaX] where SubdocumentSchemaX is a separate schema definition.
Workaround: Replaced Mongoose update logic with the native MongoDB driver's collection.updateOne() method, which successfully persists the changes.
Subdocument Array Retrieval Failure (Model B - Test Environment):

Scenario: Updating a second model document (e.g., changing status) which involves pushing a new entry to a different embedded array field (e.g., anotherSubdocumentArrayField), within Jest tests using mongodb-memory-server.
Problem: Immediately after an update operation (e.g., doc.save() or ModelB.updateOne()), attempting to read the document back using ModelB.findById() often resulted in the anotherSubdocumentArrayField array being undefined or empty, even though the update operation itself reported success. This prevented adding subsequent entries reliably.
Model: Schema B contains anotherSubdocumentArrayField: [SubdocumentSchemaY].
Workaround: Implemented conditional checks (if (Array.isArray(doc.anotherSubdocumentArrayField))) before attempting doc.anotherSubdocumentArrayField.push(...) in multiple API handlers. This allows the API to function but masks the underlying retrieval issue.
Specific Field Persistence Failure (Model B - String Field):

Scenario: Creating a new instance of Model B via POST /api/model-b or similar admin endpoint. A unique, generated reference string (specificStringField) is created before saving.
Problem: Using Mongoose doc.save() or ModelB.create() consistently failed to persist the generated specificStringField string to the database. Furthermore, Mongoose pre('save') hooks associated with the schema were observed not to run during these operations. This occurred in both development (Docker MongoDB) and test (mongodb-memory-server) environments.
Workaround: Implemented fallback logic in the API handlers. After the Mongoose save()/create() attempt, the code checks if the specificStringField field exists on the resulting document. If not, it uses the native MongoDB driver's collection.updateOne({ _id: doc._id }, { $set: { specificStringField: generatedRef } }) to force persistence. A subsequent findOne is used to ensure the API response includes the reference.
Test Environment Inconsistencies:

Diagnostic Test: A specific test confirmed that Mongoose methods (create, findById) failed to return updated subdocument arrays (anotherSubdocumentArrayField) immediately after creation/update, while equivalent raw driver methods (insertOne, findOne) worked correctly within the same test setup (mongodb-memory-server).
Impact: We have had to comment out numerous direct database state assertions in our Jest tests, relying instead on validating the API response, which incorporates the native driver workarounds. This reduces confidence in the isolated behavior of Mongoose operations within tests.
Other Test Workarounds: Disabling MongoDB transactions in the test environment due to apparent incompatibilities with mongodb-memory-server.
Implemented Workarounds Summary:

Extensive use of native MongoDB driver methods (updateOne, findOne, insertOne) to bypass problematic Mongoose operations (save, create, findById, findByIdAndUpdate).
Conditional checks before accessing potentially unpopulated/unsaved fields/arrays.
Manual construction of API response data instead of relying solely on the state of Mongoose documents post-operation.
Disabling transactions specifically in the test environment (NODE_ENV === 'test').
Removing or commenting out direct database assertions in Jest tests where Mongoose retrieval is unreliable immediately post-write.

Question:

Has anyone encountered similar silent persistence or retrieval issues with Mongoose v8.13.1, particularly concerning subdocument arrays or specific fields, especially in conjunction with Next.js API routes and/or Jest testing with mongodb-memory-server? Are there known bugs, configuration settings (Mongoose, Node.js, TypeScript, Jest, mongodb-memory-server), or potential interactions (e.g., with Next.js hot-reloading, next-auth session handling, async operations) that could explain this behavior? We are looking for insights into the root cause and potentially more robust solutions than the current native driver workarounds.

@CoderNoveau CoderNoveau added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Apr 6, 2025
@Gozubenli
Copy link

We have similar problem, the collection is not saved as expected. Some fields are updating but the fields added lately are not updating.

Frontend/Backend: Next.js (v15.2.4) with API Routes
Language: TypeScript
ODM: Mongoose (v8.13.2)
Database: MongoDB https://cloud.mongodb.com/ cluster
Authentication: next-auth (v4.24.11)

@vkarpov15
Copy link
Collaborator

I'm unable to repro, there isn't much information for us to go off of here. There aren't any issues we're aware of that might cause this sort of failure to save changes. There's our current list of warnings re: Jest, but nothing in that document is consistent with what you're seeing.

In particular, "Mongoose pre('save') hooks associated with the schema were observed not to run during these operations." is very surprising.

Please modify the following script to demonstrate the issue you're seeing. The following script seems to work as expected, but it likely doesn't match what you're doing exactly.

const mongoose = require('mongoose');

const { Schema } = mongoose;

const SubdocumentSchemaX = new Schema({
  name: String,
});

const ModelASchema = new Schema({
  title: String,
  subdocumentArrayField: [SubdocumentSchemaX],
});

const SubdocumentSchemaY = new Schema({
  status: String,
  createdAt: { type: Date, default: Date.now },
});

const ModelBSchema = new Schema({
  name: String,
  anotherSubdocumentArrayField: [SubdocumentSchemaY],
  status: String,
});

const ModelA = mongoose.model('ModelA', ModelASchema);
const ModelB = mongoose.model('ModelB', ModelBSchema);

async function main() {
  await mongoose.connect('mongodb://localhost:27017/test-subdoc-issue');
  await ModelA.deleteMany({});
  await ModelB.deleteMany({});

  // ======== Subdocument Array Persistence ========
  const a = new ModelA({
    title: 'Original A',
    subdocumentArrayField: [{ name: 'Initial X' }],
  });
  await a.save();

  console.log('\n🔄 Attempting to update ModelA using findByIdAndUpdate...');
  const updated = await ModelA.findByIdAndUpdate(
    a._id,
    { $push: { subdocumentArrayField: { name: 'Added X via $push' } } },
    { new: true }
  );
  console.log('✅ findByIdAndUpdate result:', updated);

  const checkA = await ModelA.findById(a._id);
  console.log('🔍 Retrieved ModelA from DB:', checkA);

  // ======== Subdocument Array Retrieval ========
  const b = new ModelB({
    name: 'Model B One',
    anotherSubdocumentArrayField: [],
    status: 'pending',
  });
  await b.save();

  console.log('\n🔄 Attempting to update ModelB with .save()...');
  b.anotherSubdocumentArrayField.push({ status: 'queued' });
  await b.save();

  const checkB = await ModelB.findById(b._id);
  console.log('🔍 Retrieved ModelB after update:', checkB);
  console.log(
    '❓ Is anotherSubdocumentArrayField defined:',
    Array.isArray(checkB.anotherSubdocumentArrayField)
  );
  console.log(
    '📦 anotherSubdocumentArrayField contents:',
    checkB.anotherSubdocumentArrayField
  );

  await mongoose.disconnect();
}

main().catch(console.error);

@vkarpov15 vkarpov15 added needs clarification This issue doesn't have enough information to be actionable. Close after 14 days of inactivity and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs clarification This issue doesn't have enough information to be actionable. Close after 14 days of inactivity
Projects
None yet
Development

No branches or pull requests

3 participants