情况: 我有几个相同集合(帐户)的文档,每个文档都有一个类型为array(string)的属性,名为uniquestrings.
问题: uniquestrings中的每个条目必须对mongodb中的所有文档都是唯一的.似乎MongoDB/Mongoose没有提供这样的验证(addToSet¹和index:{unique:true}²都没有解决问题).是否有一种模式来重构我的文档架构以确保mongodb本身可以验证它?目前,软件本身在更新文档之前检查它.
例如
account {
_id: 111,
uniquestrings: ["a", "b", "c"]
}
account {
_id: 222,
uniquestrings: ["d", "e", "f"]
}
Run Code Online (Sandbox Code Playgroud)
例如,account(222).uniquestrings.push("a");
通过从mongo抛出重复错误来防止.
¹数组中的唯一性是不够的
²数组中的每个项目必须在整个集合中是唯一的
UPDATE1:
更多例子.受影响的架构条目如下所示:
var Account = new Schema({
...
uniquestrings: [{type: String, index: {unique: true}}]
...
});
Run Code Online (Sandbox Code Playgroud)
现在创建4个帐户文档.我想只有1和2可以,休息应该失败.
var accountModel1 = new Account.Model({uniquestrings: ["a", "b"]});
accountModel1.save(); // OK
var accountModel2 = new Account.Model({uniquestrings: ["c", "d"]});
accountModel2.save(); // OK
var accountModel3 = new Account.Model({uniquestrings: ["c", "d"]});
accountModel3.save(); // FAIL => Not unique, so far so good
var accountModel4 = new Account.Model({uniquestrings: ["X", "d"]});
accountModel4.save(); // OK => But i Want this to faile because "d" is alreay in use.
Run Code Online (Sandbox Code Playgroud)
根据这个MongoDB Doc,没有办法强制MongoDB 在单个文档中强制执行唯一索引策略,但是有一种方法可以在单独的文档中强制执行.
db.collection.createIndex("a.b");
Run Code Online (Sandbox Code Playgroud)
......将强制执行这些a.b
......
db.collection.insert({ a: [{b: 1}] });
db.collection.insert({ a: [{b: 1}] });
Run Code Online (Sandbox Code Playgroud)
......但不会强制执行此...
db.collection.insert({ a: [{b: 1},{b: 1}] ]);
Run Code Online (Sandbox Code Playgroud)
...... 但如果你严格使用与索引...$addToSet
db.collection.upsert({ $addToSet: { a: { b: 1 } } });
Run Code Online (Sandbox Code Playgroud)
...并且你没有抛出异常而妥协,而是悄悄忽略了重复,这不是你想要的,而是更接近.
到目前为止,我们已经涵盖了另一个SO问题中的答案,但是继续阅读,也许你会得到你想要的东西.
现在,要实现您对本机MongoDB请求的要求是不可能开箱即用的,但您可以ensureIndex
使用覆盖查询来查找索引数组并在找到它时抛出错误,否则按照上面的指示进行升级.
所以...
// Ensure index
db.collection.createIndex({ 'a.b': 1 });
// Test for existence and throws up if not unique
function insertUnique(newVal) {
var exists = db.collection.find({'a.b': newVal});
if (exists) {
throw "Element is not unique in the collection: " + newVal;
} else {
db.collection.upsert({ $addToSet: { a: { b: 1 } } });
}
}
// Use it later...
try {
insertUnique(1);
insertUnique(1); // it should barf
} catch (e) {
console.warn(e);
}
Run Code Online (Sandbox Code Playgroud)
最后,根据您使用的客户端,您可以使用该insertUnique
方法扩展原型(在JS中),很快您就会忘记开始时无法执行此操作.
如果您愿意将唯一值存储在不同的集合中,则可能是可能的.它的结构如下:
{ "uniquestring" : "a", "account" : 111 }
{ "uniquestring" : "b", "account" : 111 }
{ "uniquestring" : "c", "account" : 111 }
{ "uniquestring" : "d", "account" : 222 }
{ "uniquestring" : "e", "account" : 222 }
{ "uniquestring" : "f", "account" : 222 }
Run Code Online (Sandbox Code Playgroud)
我不是Mongoose的专家,但我相信你可以定义模型来将集合链接在一起,这里的帐户字段引用了帐户集合的_id字段.
现在,您可以使用简单的索引强制实现唯一性:
db.uniquestrings.createIndex( { "uniquestring" : 1 } , { unique : true } )
Run Code Online (Sandbox Code Playgroud)
现在,您的应用程序在保存数据时需要做更多的工作(它需要保存到uniquestrings集合以及帐户集合),但现在您可以在数据库级别执行这些字符串的唯一性数据库.
任何有更多关于如何在猫鼬中实现和使用此类模型的详细知识的人都欢迎PS编辑.
归档时间: |
|
查看次数: |
1761 次 |
最近记录: |