我应该如何在猫鼬中存储价格?

cho*_*ovy 20 currency mongoose node.js

我正在为node.js使用mongoose模式以及express-validator(它具有节点验证器santiziations和验证器).

什么是存储物品价格的好方法?

我现在有

var ItemSchema = new Schema({
    name            : { type: String, required: true, trim: true }
    , price             : Number
});
Run Code Online (Sandbox Code Playgroud)

价格是可选的,所以我有:

  if ( req.body.price ) {
    req.sanitize('price').toFloat();
    req.assert('price', 'Enter a price (number only)').isFloat();
  }
Run Code Online (Sandbox Code Playgroud)

express-validator给我isNumeric(允许0填充),isDecimal和isInt ...我宁愿只转换为十进制并删除所有字符,所以我总是将42.00插入db.

我想允许他们输入42.00美元,42美元,42美元,42.00美元,只需存储42.00美元.我怎么能做到这一点?并且仍然验证我看到类似于数字的内容,例如,如果他们输入'abc',我想使用req.assert将错误返回到表单.

另外,我认为货币最终会成为一个问题......

更新,我发现这篇文章说以整数美分存储价格,所以4200 https://dba.stackexchange.com/questions/15729/storing-prices-in-sqlite-what-data-type-to-use

当我调用item.price并清理并将输入转换为4200时,我只需要一种方法将4200转换为$ 42.00.

cho*_*ovy 25

这就是我最终做的......

我在数据库中将价格存储为美分,因此如下所述,49.99为4999:https://dba.stackexchange.com/questions/15729/storing-prices-in-sqlite-what-data-type-to-use

getPrice会将其转换回可读格式,因此我可以在我的视图中使用item.price来修改它.

setPrice将其转换为美分.

模型:

var ItemSchema = new Schema({
    name            : { type: String, required: true, trim: true }
    , price             : {type: Number, get: getPrice, set: setPrice }
});

function getPrice(num){
    return (num/100).toFixed(2);
}

function setPrice(num){
    return num*100;
}
Run Code Online (Sandbox Code Playgroud)

我选择只在价格字段中允许数字和小数,而不是$.所以他们可以输入49,49.99,49.00,但不能输入49.0或49美元

使用正则表达式验证:

if ( req.body.price ) {
    req.assert('price', 'Enter a price (numbers only)').regex(/^\d+(\.\d{2})?$/);
}
Run Code Online (Sandbox Code Playgroud)

我希望有一种方法允许$因为我认为它是一个可用性问题,只需让用户输入它,但将其剥离.我不知道该怎么做,仍然证实我们有价格,而不是一堆信件.

  • 将货币存储为"数字"(内部是"双重")是有问题的,因为浮点算法本质上是不精确的.`3.3*3`变为`9.899999999999999`.`1.03 + 1.19`变为`2.2199999999999998`. (4认同)

ofh*_*use 10

提示:这里描述的方法基本上只是chovy答案的另一个实现.

Mongoose 3&4的解决方法:

如果您无法直接在架构中定义getter和setter,您还可以使用该schema.path()函数来完成此工作:

var ItemSchema = new Schema({
  name: String,
  price: Number
});

// Getter
ItemSchema.path('price').get(function(num) {
  return (num / 100).toFixed(2);
});

// Setter
ItemSchema.path('price').set(function(num) {
  return num * 100;
});
Run Code Online (Sandbox Code Playgroud)


小智 6

有点晚了但是...

\n

chovy 的答案几乎对我有用 \xe2\x80\x93 我只需要{ toJSON: { getters: true }}在模式声明中添加\n作为选项参数。

\n

例子:

\n
import mongoose from \'mongoose\'\nconst productosSchema = new mongoose.Schema(\n    {\n        name: String,\n        price: {\n            type: Number,\n            get: v => (v/100).toFixed(2),\n            set: v => v*100\n        }\n    },\n    { \n        toJSON: { getters: true } //this right here\n    }\n);\nexport default mongoose.model(\'productos\', productosSchema)\n
Run Code Online (Sandbox Code Playgroud)\n

这适用于 Mongoose 6.0.14。

\n

参考文献:https ://mongoosejs.com/docs/api.html#document_Document-toJSON

\n