如何通过 Node.js MongoDB 驱动程序向现有集合添加验证器?

4

这里有一段代码,我正在尝试向现有的集合添加验证器。

const { MongoClient } = require("mongodb")

const schema = {
  $jsonSchema: {
    bsonType: "object",
    additionalProperties: false,
    required: ["name"],
    properties: {
      _id: {
        bsonType: "objectId"
      },
      name: {
        bsonType: "string"
      }
    }
  }
}

const main = async () => {
  const client = await MongoClient.connect(
    "mongodb://localhost",
    { useNewUrlParser: true }
  )
  const db = client.db("t12")

  // await db.createCollection("test", { validator: schema })
  await db.createCollection("test")
  await db.admin().command({ collMod: "test", validator: schema })

  await db.collection("test").createIndex({ name: 1 }, { unique: true })

  await db.collection("test").insertOne({ name: "t1" })
  await db.collection("test").insertOne({ value: "t2" }) // should fail

  const all = await db
    .collection("test")
    .find({})
    .toArray()
  console.log(all)

  await client.close()
}

main().catch(err => console.error(err))

它失败了:

max7z@mbp t12__npm__mongodb (master)*$ node test/1.js
{ MongoError: ns does not exist
    at /Users/max7z/projects/t/t12__npm__mongodb/node_modules/mongodb-core/lib/connection/pool.js:581:63
    at authenticateStragglers (/Users/max7z/projects/t/t12__npm__mongodb/node_modules/mongodb-core/lib/connection/pool.js:504:16)
    at Connection.messageHandler (/Users/max7z/projects/t/t12__npm__mongodb/node_modules/mongodb-
  ok: 0,
  errmsg: 'ns does not exist',
  code: 26,
  codeName: 'NamespaceNotFound',
  name: 'MongoError',
  [Symbol(mongoErrorContextSymbol)]: {} }
^C

如果我使用该模式创建集合,则可以正常工作,但是当我尝试通过collMod添加验证器时,它会失败。
如何通过collMod命令向现有集合添加验证器?
2个回答

4

我创建了一个像这样的函数

const updateValidator = async (collectionName, newValidator) => {
    return db.command({
      collMod: collectionName,
      validator: newValidator,
      validationLevel: "moderate",
      validationAction: "warn"
   });
}
db.command 的问题在于它替换了整个验证模式。因此,您需要访问集合的当前模式。由于我没有在 nodejs 库中找到函数 db.getCollectionInfos,因此我添加了将其作为参数传递的可能性。

在我的情况下,我从其他迁移模块中使用 require 获取它。例如:

const currentValidator = require("migration-file-where-I-defined-the-previous-schema").schema.validator;

在所需文件中,我有一些初始模式,例如:
module.exports.schema = {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name"],
      properties: {
        name: {
          bsonType: "string",
          maxLength: 300,
          minLength: 3,
          description: "Must be a string and is required"
        },
        created: {
          bsonType: "date",
          description: "Date when it was created"
        },
        deleted: {
          bsonType: "date",
          description: "Date when it was deleted"
        }
      }
    },
  }
};

然后我创建一个合并新模式的操作,这就足够了。例如:

  const updatedValidator = Object.assign({}, currentValidator);
  updatedValidator.$jsonSchema.properties.new_attribX = {
    enum: ["type1", "type2"],
    description: "State of the tenant related to its life cycle"
  };
  updatedValidator.$jsonSchema.required.push('new_attribX');

  updateValidator("mycollection", updatedValidator)
    .then(next)
    .catch(console.error);

这将使用已应用更改的新模式替换先前的模式。对我来说,这已经足够了,但请记住,当您有现有数据需要使用新数据更新时,您需要使用类似以下的方式进行更新:

collection.updateMany({'new_attribX': {$exists : false}}, {$set: {'new_attribX': 'type1'}});

对于没有属性new_attribX的数据,它应该添加这种初始默认值:type1

我希望这可以帮到你。


1
问题出在这一行代码上: await db.admin().command({ collMod: "test", validator: schema }) 正确的做法是: await db.command({ collMod: "test", validator: schema })

问题是这会替换模式,而不是更新它。 - EliuX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接