MongoDB防止字段相等的文档

时间:2019-07-25 22:29:35

标签: mongodb mongodb-query

如果两个字段相等,是否可以防止Mongo创建文档?

例如,这应该被接受:

{ A: 'foo', B: 'bar' }

但这应该被拒绝:

{ A: 'foo', B: 'foo' }

在调用Mongo之前执行检查很简单,但是这样做的目的是防止从shell修改集合后发生错误。

为了清楚起见,我并不是要比较一个文档的字段与另一个文档的字段。文档中的值不能与同一文档中的其他值冲突。

1 个答案:

答案 0 :(得分:1)

实际上,做到这一点很容易,尽管有一个警告,但我无法以令人满意的方式解决。

有一个叫做schema validation的东西。我们将使用它,但是我们使用query expression代替了实际的JsonSchema。

> db.runCommand({
  // We modify an existing collection named "validate"...
  collMod:"validate",
  // ...adding a validator...
  "validator":{
    // ...ensuring that documents are only considered valid if
    // the value of field A is not equal the value of field B
    $expr:{$ne:["$A","$B"]}}
  }
)
{ "ok" : 1 }

让我们对其进行测试:

> db.validate.insert({"A":"foo","B":"bar"})
WriteResult({ "nInserted" : 1 })
> db.validate.insert({"A":"foo","B":"foo"})
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})

是的,到目前为止看起来还不错,不是吗?除此之外,有一个警告:

> db.validate.insert({"A":"foo","B":"foo "})
WriteResult({ "nInserted" : 1 })

一个简单的空白实际上可以击败我们的一点平等检查。因此,显然我们需要扩展验证器:

db.runCommand({collMod:"validate","validator":{$and:[
    // Both A and B must not have leading or trailing white space.
    {"A":{$regex:/^\w+$/}},
    {"B":{$regex:/^\w+$/}},
    // As before.
    {$expr:{$ne:["$A","$B"]}}
]}})

所以,让我们重新检查一下:

db.validate.deleteMany({})
{ "acknowledged" : true, "deletedCount" : 2 }
> db.validate.insert({"A":"foo","B":"bar"})
WriteResult({ "nInserted" : 1 })
> db.validate.insert({"A":"foo","B":"bar "})
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})
> db.validate.insert({"A":"foo","B":"foo"})
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})

似乎可以正常工作。但是,用户无法找出为什么文档验证失败。如果可以忍受,那么您有解决方案。 就个人而言,我宁愿使用专用的CLI工具进行修改,并事先验证输入。生产数据库的数据修改不应使用DBMS CLI。

此外,还有一些与用例相关的问题:“ foo”是否等于“ Foo”和“ FOO”?如果是这样,当A持有“ fOo”而B持有“ foO”时,A和B是否相等?依此类推。