22

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

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

我目前有

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

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

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

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 美元的方法。

4

6 回答 6

30

这就是我最终做的...

我将价格作为美分存储在数据库中,因此 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;
}

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

使用正则表达式验证:

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

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

于 2012-11-09T09:23:07.707 回答
14

提示:这里描述的方法基本上只是chovy 的 answer 的另一种实现。

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;
});
于 2016-04-16T18:22:29.073 回答
3

将模式类型“货币”添加到 mongoose 以处理金钱。自动去除常用字符(“,”,“$”和字母字符)

https://github.com/paulcsmith/mongoose-currency

它能做什么:

将字符串保存为整数(通过去除非数字并乘以 100)以防止在执行计算时出现舍入错误(有关详细信息,请参阅陷阱)从字符串的开头去除符号(有时用户包括货币符号)去除逗号(有时用户添加逗号或将粘贴值复制到表单中,例如“1,000.50”仅保存小数点后两位(“$500.559”转换为 50055 并且不四舍五入)从字符串中去除 [a-zA-Z] 传入字符串或数字。数字将按原样存储。假设如果您将值设置为整数,则您已经完成了转换(例如 50000 = $500.00)如果传入浮点数,它将对其进行舍入。(500.55 -> 501). 只需传入整数以确保安全。

希望它可以帮助一些。

于 2016-05-01T22:55:42.197 回答
3

有点晚了,但是...

chovy的答案几乎对我有用——我只需要 { toJSON: { getters: true }}在模式声明中添加一个选项参数。

例子:

import mongoose from 'mongoose'
const productosSchema = new mongoose.Schema(
    {
        name: String,
        price: {
            type: Number,
            get: v => (v/100).toFixed(2),
            set: v => v*100
        }
    },
    { 
        toJSON: { getters: true } //this right here
    }
);
export default mongoose.model('productos', productosSchema)

这适用于猫鼬 6.0.14。

参考资料:https ://mongoosejs.com/docs/api.html#document_Document-toJSON

于 2021-12-03T22:48:56.640 回答
1

我一直在研究这个主题,因为我不仅想存储价格,还想存储版本,它们都可能有尾随的 0,当存储为数字时会被截断。据我所知,Mongoose/MongoDB 无法保存带有尾随零的数字。

除非您将数字保存为字符串。

除了存储数以万计或以千计的数字并进行分割或解析之外,您还可以将其存储为字符串。这意味着,当您需要显示“1.0”或“1.00”时,您可以随时打印出来,只需使用变量而不进行任何转换。由于 JavaScript 没有类型,您仍然可以将其与数字进行比较(确保它在左侧)。例如,var < 10 将返回正确的评估,即使 var 是字符串也是如此。但是,如果您要比较两个变量,则需要确保它们都是数字。当您需要一个数字时,您可以将字符串乘以 1 (var * 1 < var2 * 1),这将确保 JavaScript 将 var 视为一个数字,尽管它会丢失尾随的零。

一方面,将其存储为字符串意味着每次要将变量用作数字时都需要进行转换。另一方面,每次您想将美分数字用作美元金额时,您可能都会进行数字转换(var / 100)。此选项取决于您需要将值作为数字的频率。此外,如果您忘记变量是字符串,则可能会导致更大的错误,而不是忘记变量以美分为单位。

(但是,它非常适合仅用于显示和比较的版本号。)

于 2013-01-13T02:28:53.443 回答
0

数字模块将完成: http : //numeraljs.com/ https://www.npmjs.com/package/numeral

于 2015-07-13T05:54:11.477 回答