猫鼬,使用字符串与布尔值的文档状态
Mongoose, document state using String vs Booleans
您好,我想知道在保存文档的 "state" 时有什么更好的方法吗?我能想到的两种方法是使用字符串结束枚举:
const proposal = new Schema({
state: {
type: String,
enum: ['pending', 'approved', 'denied'],
default: 'pending'
}
});
或使用布尔值:
const proposal = new Schema({
approved: {
type: Boolean,
default: false
},
denied: {
type: Boolean,
default: false
}
});
就性能和安全性而言,哪个更好?从表面上看,搜索 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
}
});
假设
proposalA
表示文档状态只能是'pending'、'approved'、'denied'三个值之一。
proposalB
表示为了支持 proposalA
的假设,那么对于 'pending' 状态,'approved' 和 'denied' 都为假。
担忧
查询、索引和修改
虽然 proposalA
确实使用了字符串值,但任一提议的匹配都是相等性检查,{ state : 'approved' }
或 { approved: true }
用于搜索查询。最大的不同是 pending
:
proposalA
: { state: 'pending' }
proposalB
: { approved: false, denied: false }
假设没有其他查询参数,这将需要 single index on state
for proposalA
while proposalB
would require two indexes, one each for approved
and denied
, and to use mongo's index intersection or a compound index of approved
和 denied
.
将其留给索引交集的问题在于,如果查询变得更加复杂,那么由于各种原因,预测将使用哪个交集的能力将变得非常棘手。例如,目前只有3个状态,如果添加新状态,则需要创建更多索引以确保查询高效。
这会导致另一个问题,即每个索引在 mongo 服务器的内存中占用 space。虽然复合索引将此查询的索引数量减少到一个,但对于 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
}
虽然需要使用一些条件代码来构造 proposalB
的查询(此逻辑的可能变体):
function getDocsFromState(state) {
const Foo = mongoose.Model('foo');
const query = {
approved: state === 'approved',
denied: state === 'denied'
};
return Foo.find(query).exec(); // Promise
}
除了 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
}
虽然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
}
条件逻辑与验证
通过使用多个字段来表示每个枚举值来模拟枚举时,验证变得有点麻烦。根据定义,枚举可防止一次存储多个值,proposalB
需要使用验证来防止 approved
和 denied
同时为真。强制执行此操作可能会限制更新方法(部分更新与保存前更新内存中的完整文档),具体取决于所使用的验证工具(本机 mongo 与第三方库 mongoose)到更新文档。
最后,我们已经了解了条件逻辑对于查询和更新文档的必要性,但代码中的其他区域可能需要这样做。任何时候 proposalB
内存中的文档需要检查其当前状态都需要使用类似的条件逻辑,而 proposalA
只需检查枚举值。
TL;DR;
我们已经看到枚举如何提供内置文档验证、减少文档和索引大小、简化索引策略、简化当前和可能的未来实现代码,并且最终在查询中几乎没有性能问题,因为这两种方法都使用相等性检查。
希望对您有所帮助!
您好,我想知道在保存文档的 "state" 时有什么更好的方法吗?我能想到的两种方法是使用字符串结束枚举:
const proposal = new Schema({
state: {
type: String,
enum: ['pending', 'approved', 'denied'],
default: 'pending'
}
});
或使用布尔值:
const proposal = new Schema({
approved: {
type: Boolean,
default: false
},
denied: {
type: Boolean,
default: false
}
});
就性能和安全性而言,哪个更好?从表面上看,搜索 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
}
});
假设
proposalA
表示文档状态只能是'pending'、'approved'、'denied'三个值之一。
proposalB
表示为了支持 proposalA
的假设,那么对于 'pending' 状态,'approved' 和 'denied' 都为假。
担忧
查询、索引和修改
虽然 proposalA
确实使用了字符串值,但任一提议的匹配都是相等性检查,{ state : 'approved' }
或 { approved: true }
用于搜索查询。最大的不同是 pending
:
proposalA
:{ state: 'pending' }
proposalB
:{ approved: false, denied: false }
假设没有其他查询参数,这将需要 single index on state
for proposalA
while proposalB
would require two indexes, one each for approved
and denied
, and to use mongo's index intersection or a compound index of approved
和 denied
.
将其留给索引交集的问题在于,如果查询变得更加复杂,那么由于各种原因,预测将使用哪个交集的能力将变得非常棘手。例如,目前只有3个状态,如果添加新状态,则需要创建更多索引以确保查询高效。
这会导致另一个问题,即每个索引在 mongo 服务器的内存中占用 space。虽然复合索引将此查询的索引数量减少到一个,但对于 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
}
虽然需要使用一些条件代码来构造 proposalB
的查询(此逻辑的可能变体):
function getDocsFromState(state) {
const Foo = mongoose.Model('foo');
const query = {
approved: state === 'approved',
denied: state === 'denied'
};
return Foo.find(query).exec(); // Promise
}
除了 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
}
虽然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
}
条件逻辑与验证
通过使用多个字段来表示每个枚举值来模拟枚举时,验证变得有点麻烦。根据定义,枚举可防止一次存储多个值,proposalB
需要使用验证来防止 approved
和 denied
同时为真。强制执行此操作可能会限制更新方法(部分更新与保存前更新内存中的完整文档),具体取决于所使用的验证工具(本机 mongo 与第三方库 mongoose)到更新文档。
最后,我们已经了解了条件逻辑对于查询和更新文档的必要性,但代码中的其他区域可能需要这样做。任何时候 proposalB
内存中的文档需要检查其当前状态都需要使用类似的条件逻辑,而 proposalA
只需检查枚举值。
TL;DR;
我们已经看到枚举如何提供内置文档验证、减少文档和索引大小、简化索引策略、简化当前和可能的未来实现代码,并且最终在查询中几乎没有性能问题,因为这两种方法都使用相等性检查。
希望对您有所帮助!