Mongoose,使用字符串与布尔值的文档状态

Mongoose,使用字符串与布尔值的文档状态,mongoose,state,document,mongoose-schema,Mongoose,State,Document,Mongoose Schema,您好,我想知道在保存文档的“状态”时,什么是更好的方法?我可以想到的两种方法是使用字符串结束枚举: const proposal = new Schema({ state: { type: String, enum: ['pending', 'approved', 'denied'], default: 'pending' } }); 或使用布尔值: const proposal = new Schema({ approv

您好,我想知道在保存文档的“状态”时,什么是更好的方法?我可以想到的两种方法是使用字符串结束枚举:

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
    }
});

哪一个在性能和安全性方面更好?在外部,搜索“<代码> BooLangs<代码>比<代码>字符串 Stry.< /P> < P> >在搜索的关注之外还有其他一些事情要考虑,例如:条件逻辑;设定值;验证文档、文档大小;和索引

让我们回顾两个建议的模式,并使用enum将它们命名为
proposalA
,使用多个字段模拟enum将它们命名为
proposalB

const proposalA=新模式({
声明:{
类型:字符串,
枚举:[“待定”、“已批准”、“已拒绝”],
默认值:“待定”
}
});
const proposalB=新模式({
核准:{
类型:布尔型,
默认值:false
},
否认:{
类型:布尔型,
默认值:false
}
});
假设
proposalA
表示文档状态只能是三个值之一:“待定”、“已批准”和“已拒绝”。
proposalB
表示为了支持
proposalA
的假设,对于“待定”状态,“批准”和“拒绝”都是假的

担心 查询、索引和修改 虽然
proposalA
确实使用字符串值,但两个方案的匹配都是平等性检查,
{state:'approved'}
{approved:true}
用于搜索查询。最大的区别在于
挂起的

  • proposalA
    {state:'pending'}
  • proposalB
    {批准:错误,拒绝:错误}
假设没有其他查询参数,这将要求
proposalA
状态为on
,而
proposalB
将需要两个索引,分别用于
approved
denied
,并使用mongo或
approved
denied

将其留给索引交叉点的问题是,如果查询变得更加复杂,那么由于各种原因,预测将使用哪个交叉点的能力变得非常棘手。例如,目前只有3个状态,如果添加了新的状态,则需要创建更多的索引以确保查询的效率

这导致了另一个问题,即每个索引都会占用mongo服务器的内存空间。虽然复合索引将此查询的索引数减少为一个,但对于
proposalA
,它可能仍然是内存中比单个索引更大的索引

说到内存大小,
{state:'pending'}
的文档大约是
{approved:false,denied:false}
的一半大小。虽然目前这似乎微不足道,但如前所述,如果添加更多的状态或在其他字段中继续使用此模式,则很容易看到文档大小也会快速膨胀

从编程的角度返回搜索查询显示
proposalA
非常简单:

函数getDocsFromState(状态){ const Foo=mongoose.Model('Foo'); const query={state};//假设状态是一个字符串'pending'、'approved'或'denied' 返回Foo.find(query.exec();//Promise }
虽然需要使用一些条件代码来构造
proposalB
的查询(此逻辑的一个可能变体):

函数getDocsFromState(状态){ const Foo=mongoose.Model('Foo'); 常量查询={ 已批准:状态==“已批准”, 已拒绝:状态===“已拒绝” }; 返回Foo.find(query.exec();//Promise }
除了
proposalA
有更简洁的代码外,它不需要实现更新来支持新的状态,而
proposalab
则需要它们

同样的问题也适用于更新状态的值<代码>提案保持简洁:

函数updatedcstate(_id,state){
const Foo=mongoose.Model('Foo');
const update={state};//假设状态是一个字符串“pending”、“approved”或“denied”
返回Foo.update({u id},update).exec();//Promise
}
虽然
proposalB
仍需要更多的附加逻辑:

函数updatedcstate(_id,state){
const Foo=mongoose.Model('Foo');
常数更新={
已批准:状态==“已批准”,
已拒绝:状态===“已拒绝”
};
返回Foo.update({u id},update).exec();//Promise
}
条件逻辑与验证 通过使用多个字段来表示每个枚举值来模拟枚举时,验证会变得有点麻烦。根据定义,枚举防止一次存储多个值,
proposalB
需要使用验证来防止
approved
denied
同时为真。强制执行此操作可能会限制更新方法(部分更新与保存前更新内存中的完整文档),具体取决于用于更新文档的验证工具(本机mongo与第三方库,如mongoose)

最后,我们已经了解了查询和更新文档时条件逻辑的必要性,但代码中可能还有其他需要条件逻辑的地方。每当需要检查
proposalB
内存中的文档的当前状态时,都需要使用类似的条件逻辑,而
proposalA
只需检查枚举值

TL;博士 我们已经了解了枚举如何提供内置文档验证、减少文档和索引大小、简化索引策略、简化当前和可能的未来