Com*_*zza 3 state document mongoose mongoose-schema
您好,我想知道在保存文档的“状态”方面有什么更好的方法?我能想到的两种方法是使用字符串结尾枚举:
const proposal = new Schema({
state: {
type: String,
enum: ['pending', 'approved', 'denied'],
default: 'pending'
}
});
Run Code Online (Sandbox Code Playgroud)
或使用布尔值:
const proposal = new Schema({
approved: {
type: Boolean,
default: false
},
denied: {
type: Boolean,
default: false
}
});
Run Code Online (Sandbox Code Playgroud)
在性能和安全性方面,哪一个更好?在外面,搜索似乎booleans比string搜索更快。
除了关注搜索之外,还有一些其他的事情需要考虑,例如: 条件逻辑;设定值;验证文件、文件大小;和索引。
让我们回顾一下两个提议的模式并命名它们proposalA,使用枚举,和proposalB使用多个字段来模拟枚举:
const proposalA = new Schema({
state: {
type: String,
enum: ['pending', 'approved', 'denied'],
default: 'pending'
}
});
const proposalB = new Schema({
approved: {
type: Boolean,
default: false
},
denied: {
type: Boolean,
default: false
}
});
Run Code Online (Sandbox Code Playgroud)
proposalA表示文档状态只能是以下三个值之一:'pending'、'approved' 和 'denied'。
proposalB表示支持proposalAthen 对于“待定”状态的假设,“批准”和“拒绝”都是错误的。
虽然proposalA确实使用了字符串值,但任一提议的匹配都是相等性检查{ state : 'approved' }或{ approved: true }搜索查询。最大的区别在于pending:
proposalA: { state: 'pending' }proposalB: { approved: false, denied: false }假设没有其他查询参数,这将需要一个单独的索引上state用于proposalA同时proposalB将需要两个索引,每一个用于approved和denied,并使用蒙戈的索引交集或化合物指数的approved和denied。
将它留给索引交集的问题是,如果查询变得更加复杂,那么由于各种原因,预测将使用哪个交集的能力变得非常棘手。例如,目前只有 3 个状态,如果添加新状态,则需要创建更多索引以确保查询高效。
这导致了每个索引占用 mongo 服务器内存空间的另一个问题。虽然复合索引将这个查询的索引数量减少到一个,但它可能仍然是内存中比单个索引更大的proposalA.
说到内存大小,一个文档{ state: 'pending' }大约是{ approved: false, denied: false }. 虽然目前这看起来微不足道,但如前所述,如果添加更多状态或在其他字段中继续这种模式,那么很容易看出文档大小也会很快膨胀。
从编程的角度返回搜索查询表明这proposalA非常简单:
function getDocsFromState(state) {
const Foo = mongoose.Model('foo');
const query = { state }; // assuming state is a string of 'pending', 'approved', or 'denied'
return Foo.find(query).exec(); // Promise
}
Run Code Online (Sandbox Code Playgroud)
虽然需要使用一些条件代码来构造查询proposalB(此逻辑的可能变体):
function getDocsFromState(state) {
const Foo = mongoose.Model('foo');
const query = {
approved: state === 'approved',
denied: state === 'denied'
};
return Foo.find(query).exec(); // Promise
}
Run Code Online (Sandbox Code Playgroud)
除了proposalA拥有更简洁的代码之外,它不需要实现更新来支持新状态,而proposalB需要它们。
同样的问题适用于更新状态的值。proposalA保持简洁:
function updateDocState(_id, state) {
const Foo = mongoose.Model('foo');
const update = { state }; // assuming state is a string of 'pending', 'approved', or 'denied'
return Foo.update({ _id }, update).exec(); // Promise
}
Run Code Online (Sandbox Code Playgroud)
虽然proposalB仍然需要更多额外的逻辑:
function updateDocState(_id, state) {
const Foo = mongoose.Model('foo');
const update = {
approved: state === 'approved',
denied: state === 'denied'
};
return Foo.update({ _id }, update).exec(); // Promise
}
Run Code Online (Sandbox Code Playgroud)
通过使用多个字段来表示每个枚举值来模拟枚举时,验证变得有点麻烦。根据定义,枚举可防止一次存储多个值,proposalB需要使用验证来防止两者approved同时denied为真。根据用于更新文档的验证工具(本机 mongo 与 mongoose 等 3rd 方库),强制执行此操作可能会限制更新方法(部分更新与在保存之前更新内存中的完整文档)。
最后,我们已经看到条件逻辑对于查询和更新文档是多么必要,但代码中可能还有其他地方可能需要这样做。任何时候proposalB需要检查内存中的文档的当前状态时,都需要使用类似的条件逻辑,而proposalA只需检查枚举值。
我们已经看到枚举如何提供内置文档验证、减少文档和索引大小、简化索引策略、简化当前和未来可能的实现代码,并最终在查询中几乎没有性能问题,因为这两种方法都使用等式检查。
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
570 次 |
| 最近记录: |