问题 是否存在将基于字符串的JSON转换为Mongoose Schema对象实例的本机功能?


我正在使用Express,我正在寻找一种方便的方法来转换这种对象(来自请求 req.body.myObject):

{
  "name": "Foo",
  "someNumber": "23",
  "someBoolean": "on"
}

进入这个Schema的一个实例:

var myObjectSchema = new Schema({
    name: String,
    someNumber: Number,
    someBoolean: Boolean
});

请注意,第一个对象来自请求,因此完全由Strings完成。

有没有一些很好的方法来实现这一目标?如果没有,您对如何将此功能实现为中间件有任何建议吗?


2944
2017-08-21 03:31


起源

“请注意,第一个对象来自请求,因此完全由Strings完成。”  - 为什么不更改它以在适当的位置返回数字和布尔值?你在我引用的句子中使用“so”意味着只允许使用字符串,但如果它是JSON则不是这样。 (也就是说,JSON本身是一种基于字符串的格式,但它可以 代表 数字和布尔值,当解析JSON时,这些属性变成数字和布尔...) - nnnnnn
您的架构中的属性是固定的,还是需要它们是动态的? - Mahn
@nnnnn嗯,问题是Express从表单中获取信息 myObject[name]:name, myObject[someNumber]:23和Express本身默认情况下构造myObject,将每个属性设置为String! - Renato Gama
@Mahn他们是静止的! - Renato Gama


答案:


通过引用这个线程 Mongoose:将JS对象直接插入db 我发现是的,这是一个内置功能。

您只需构建一个新模型,将请求值(来自表单)作为参数传递:

function add(req, res){
    new Contact(req.body.contact).save(function(err){
        console.log("Item added");
        res.send();
    });
};

它会自动为您转换内容!


10
2017-08-22 18:47



你不需要在联系人面前有一个“新”。这在节点上很昂贵。 function add(req,res){Contact(req.body.contact).save(function(err){console.log(“Item added”); res.send();}); }; - fino
嗨@fino,谢谢你的建议!你能提供任何资源吗? new 节点昂贵?作为初学者,我还没有听说过它!谢谢 - Renato Gama
很多原因,埃里克在这里有一些好的 ericleads.com/2012/09/... 。对于nodejs,搜索nodejs内存管理和堆大小。 - fino
谢谢@fino,肯定会看看! - Renato Gama


我知道这个答案已被接受了,但我想指出,猫鼬为你照顾大部分的演员......大部分时间。虽然mongoose这样做很方便,但它抽象了mongo的真实行为。例如,mongoose允许你做这样的事情:

PersonModel.findById("4cdf00000000000000007822", ...);

但是,如果您尝试直接查询数据库(没有mongoose),这样就可以了  工作:

PersonCollection.find({_id: "4cdf00000000000000007822"}, ...);

这是因为ObjectIds不是字符串......它们是对象。在内部,mongoose将该字符串转换为ObjectId,然后对数据库执行查询,以便最终查询看起来像这样:

PersonCollection.find({_id: ObjectId("4cdf00000000000000007822")}, ...);

此外,模式中的每个路径都有一个“脚轮”方法。这是一种私有方法,但在您需要它时它会非常方便。 请注意那个 caster 下面描述的方法是未经授权的,并且可以在没有警告的情况下进行更改。自行承担使用风险 (抱歉叫喊):

// Use PersonModel.schema.paths() to get all paths and loop over them if you want
var key = "name";
var pathObj = PersonModel.schema.path( key );
if( !pathObj ) pathObj = PersonModel.schema.virtualpath( key );
if( !pathObj ) { /* not found: return, continue, exit, whatever */ }

// UNDOCUMENTED: USE AT YOUR OWN RISK
var caster = pathObj.caster || pathObj;
var castedValue = caster.cast( req.body.name );

为什么我知道这个?因为如果你想使用mongo的一些更高级的功能,比如聚合,你需要在构建管道时投射你自己的值。我还需要为使​​用的某些查询手动转换值 $in 操作员...也许这不再需要了。重点是,如果您在获得预期结果时遇到问题,请尝试自己投射值。


2
2017-08-26 22:24



在研究之后,你会想到在生产中使用它。哎呀! - Joshua Michael Calafell
不是单元测试...人们经常使用未记录的功能,如果你测试你的代码,你是100%安全的。如果该方法消失,您的测试将在您开始生产之前很久就会显示它并进行修复。我也警告你自担风险。如果你不写测试,那就是你的问题,这是你冒的风险;) - Ryan Wheale


如果模式是静态的,理论上可以采用惰性,非复杂的方式,只需硬编码值而不是传递对象本身:

var someObject = {
    name: "Foo",
    someNumber: "23",
    someBoolean: "on"
}

var myObjectSchema = new Schema({
    name: someObject.name,
    someNumber: parseInt(someObject.someNumber, 10),
    someBoolean: (someObject.someBoolean == "on")
});

可能不是您正在寻找的答案,但如果没有更好的可能,可能需要考虑。


0
2017-08-21 04:15



如你所愿,我正在寻找一种通用的方法,而不必每次编写新的Schema时都重写它。 - Renato Gama