You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中MongoDB集合$jsonSchema验证失效问题求助

Fixing $jsonSchema Validation Not Working with MongoDB Node.js Driver

Let's break down why your $jsonSchema validation isn't taking effect and fix it step by step:

Key Issues in Your Current Code

  1. Existing Collection Skipping Validation: When you call db.createCollection() on an already-existing collection, MongoDB ignores the validator options entirely. This is the most likely reason your validation isn't working—if you ran the code before setting up validation, the collection was created without it, and subsequent runs don't update it.
  2. Uncontrolled Async Flow: Your doValidation and doIndexing methods run asynchronously without waiting for each other to complete. This can lead to race conditions (like trying to create an index before the collection is properly configured) and makes debugging harder.
  3. Schema Target Mismatch: Your test schema targets a test field instead of the code field you mentioned needing validation.

Step-by-Step Solution

1. Handle Existing Collections with collMod

To apply validation to both new and existing collections, we'll check if the collection exists first. If it does, we use the collMod command to update its validation rules. If not, we create it with the validator.

2. Use async/await for Predictable Async Flow

This ensures we only create indexes after the collection's validation rules are fully set up, and makes the code easier to read and debug.

3. Explicitly Set Validation Enforcement

We'll add validationLevel: "strict" and validationAction: "error" to ensure all write operations are blocked if they don't match the schema.


Modified Working Code

const BaseRepository = require('../../../db/baseRepository');
const getMongoDBClient = require('../../../db/mongodbClient');

class LanguageRepository //extends BaseRepository
{
  constructor() {
    this.collectionName = 'languages';
    this.dbClient = getMongoDBClient();
    // Initialize validation and indexing properly
    this.init();
  }

  async init() {
    try {
      const db = await this.dbClient;
      // Check if the collection already exists
      const existingCollections = await db.listCollections({ name: this.collectionName }).toArray();
      
      if (existingCollections.length === 0) {
        // Create new collection with validation rules
        await this.createCollectionWithValidation(db);
      } else {
        // Update validation rules for existing collection
        await this.updateCollectionValidation(db);
      }

      // Create index after collection is properly configured
      await this.createIndex(db);
      console.log('Language collection initialized with validation and index successfully');
    } catch (err) {
      console.error('Failed to initialize Language repository:', err);
    }
  }

  async createCollectionWithValidation(db) {
    await db.createCollection(this.collectionName, {
      validator: {
        $jsonSchema: {
          bsonType: "object",
          required: ["code"], // Enforce code is always present
          properties: {
            code: {
              bsonType: "string",
              pattern: "^[a-zA-Z]{2}$", // Enforce 2-letter alphabetic code
              description: "Must be a 2-letter uppercase/lowercase alphabetic string"
            },
            test: {
              bsonType: "int",
              minimum: 2017,
              maximum: 3017,
              description: "Must be an integer between 2017 and 3017"
            }
          }
        }
      },
      // Ensure all writes (including updates) follow the schema
      validationLevel: "strict",
      // Block invalid writes instead of just warning
      validationAction: "error"
    });
  }

  async updateCollectionValidation(db) {
    await db.command({
      collMod: this.collectionName,
      validator: {
        $jsonSchema: {
          bsonType: "object",
          required: ["code"],
          properties: {
            code: {
              bsonType: "string",
              pattern: "^[a-zA-Z]{2}$",
              description: "Must be a 2-letter alphabetic string"
            },
            test: {
              bsonType: "int",
              minimum: 2017,
              maximum: 3017,
              description: "Must be an integer between 2017 and 3017"
            }
          }
        }
      },
      validationLevel: "strict",
      validationAction: "error"
    });
  }

  async createIndex(db) {
    const keys = { code: 1 };
    const options = { sparse: true, unique: true };
    await db.collection(this.collectionName).createIndex(keys, options);
  }

  async add(item) {
    const db = await this.dbClient;
    return db.collection(this.collectionName).insertOne(item);
  }
}

module.exports = LanguageRepository;

How to Test It

  1. If you already have a languages collection without validation, run this code—it will update the collection to enforce the schema.
  2. Try inserting an invalid document, like:
    const repo = new LanguageRepository();
    repo.add({ code: '12', test: 2016 }).catch(err => console.log(err));
    
    You should get an error blocking the insertion, confirming validation is working.

内容的提问来源于stack exchange,提问作者Mohammed Al-Hanabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:50:27