如何限制mongodb中父节点的最大引用

for*_*orJ 6 database tree mongodb node.js

我必须mongodb使用官方文档(父母引用,子引用,祖先数组,物化路径,嵌套集)建议的四种方法创建一个树结构,我决定使用它,array of ancestors因为树的层级会很深可能有数千个级别或更多.所以我认为存储中的惩罚可以通过更快的速度来补偿,因为在查找节点的所有父节点时需要较少的查询.

问题是树必须是严格的二进制.因此,例如节点1将只有节点2和节点3作为其子节点而不再具有节点.不幸的是,我现在只能想到这样做是为了找到所有引用我想在下一个文档中引用的特定父级的文档,如果计数不超过2,我会插入引用目标父级的文档.

显然问题是mongodb的多线程性质,即使它不是,查询引用目标父级的计数的请求可能介于扫描和插入前一个文档之间,如果有的话会导致第三次插入一个文档已经引用了目标父级.

有没有办法可以确保只有两个节点可以引用mongodb和服务器的多线程环境中的父节点?

Sar*_*ana 3

$jsonSchema如果您使用的是 mongo 版本 3.6,您可以在服务器端使用模式验证

我们更新/插入的每个文档都将根据验证模式进行验证,如果验证失败,将抛出错误并且不会对文档进行任何修改

样本node收集模式

{
   _id : string,
   parent : [string, null],
   children : string[2]
}
Run Code Online (Sandbox Code Playgroud)

验证模式

db.createCollection("node", {
   validator: {
      $jsonSchema: {
         bsonType: "object",
         required: [ "_id" ],
         properties: {
            parent: {
               bsonType: ["string", "null"],
               description: "must be a string"
            },
            children: {
               bsonType: ["array"],
               items : { bsonType: ["string"] },
               minItems: 0,
               maxItems: 2,
               description: "must be a array of string and max is 2"
            }
         }
      }
   }
});
Run Code Online (Sandbox Code Playgroud)

插入[带有有效文件]

> db.node.insert( { _id: "Books", children: [ "Programming" ], parent: null } )
WriteResult({ "nInserted" : 1 })
> db.node.insert( { _id: "Programming", children: [ "Databases", "Languages" ], parent: "Books" } )
WriteResult({ "nInserted" : 1 })
> db.node.insert( { _id: "Languages", children: [ ], parent: "Programming" } )
WriteResult({ "nInserted" : 1 })
> db.node.insert( { _id: "Databases", children: [ "MongoDB", "dbm" ], parent: "Programming" } )
WriteResult({ "nInserted" : 1 })
> db.node.insert( { _id: "MongoDB", children: [ ], parent: "Databases" } )
WriteResult({ "nInserted" : 1 })
> db.node.insert( { _id: "dbm", children: [ ], parent: "Databases" } )
WriteResult({ "nInserted" : 1 })
> 
Run Code Online (Sandbox Code Playgroud)

寻找

> db.node.find()
{ "_id" : "Books", "children" : [ "Programming" ], "parent" : null }
{ "_id" : "Programming", "children" : [ "Databases", "Languages" ], "parent" : "Books" }
{ "_id" : "Languages", "children" : [ ], "parent" : "Programming" }
{ "_id" : "Databases", "children" : [ "MongoDB", "dbm" ], "parent" : "Programming" }
{ "_id" : "MongoDB", "children" : [ ], "parent" : "Databases" }
{ "_id" : "dbm", "children" : [ ], "parent" : "Databases" }
Run Code Online (Sandbox Code Playgroud)

插入无效文档 [子尺寸 > 2]

> db.node.insert({_id : "1", children : ["c1", "c2", "c3"], parent : "p1"})
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})
> 
Run Code Online (Sandbox Code Playgroud)

插入失败并出现验证错误

更新 - 尝试为 _id 数据库添加第三个子级,失败并出现验证错误

> db.node.updateOne( { _id: "Databases"}, {$push : {children: [ "Oracle" ]}} )
2018-02-25T21:00:08.087+0530 E QUERY    [thread1] WriteError: Document failed validation :
WriteError({
    "index" : 0,
    "code" : 121,
    "errmsg" : "Document failed validation",
    "op" : {
        "q" : {
            "_id" : "Databases"
        },
        "u" : {
            "$push" : {
                "children" : [
                    "Oracle"
                ]
            }
        },
        "multi" : false,
        "upsert" : false
    }
})
WriteError@src/mongo/shell/bulk_api.js:466:48
Bulk/mergeBatchResults@src/mongo/shell/bulk_api.js:846:49
Bulk/executeBatch@src/mongo/shell/bulk_api.js:910:13
Bulk/this.execute@src/mongo/shell/bulk_api.js:1154:21
DBCollection.prototype.updateOne@src/mongo/shell/crud_api.js:572:17
@(shell):1:1
> 
Run Code Online (Sandbox Code Playgroud)

请参阅schema-validationjsonSchema了解更多选项,向现有集合添加验证并处理验证失败