我正在创建一个应用程序,用户可以在其中创建各种类型的自定义字段,我想将这些字段存储在mongo中。类型将包括字符串,数字和日期。我的架构如下所示:
const MetaSchema = new mongoose.Schema({
key: String,
value: {type: mongoose.Schema.Types.Mixed},
type: String,
created_at: {type: Date, default: Date.now}
});
这很好用,我可以按预期存储我的数据。问题是,当我想存储一个日期时,它会以ISO格式发送到服务器,有效负载可能如下所示:
{
"key": "Contract Signed",
"value": "2016-04-06T22:35:11.540Z",
"type": "date"
}
任何方式我都可以得到mongo / mongoose来处理和存储这个像日期而不是字符串?如果我将其设置为键入日期,那么我认为它可以解决问题,但我必须保存他们可以为自定义字段提供的任何内容。非常感谢!
TLDR:根据插入的数据类型(IE Date vs String),可以对mongoose / mongo中的混合数据类型进行不同的处理。
答案 0 :(得分:2)
使用mongoose discriminators可能就是这里的方法。他们实际上使用他们自己的"类型" (默认__t
但可以覆盖)存储文档中的属性,允许mongoose实际应用一种"模型"使用它自己的附加架构来对每个对象。
作为一个简短的例子:
var async = require('async'),
util = require('util'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/things');
mongoose.set("debug",true);
function BaseSchema() {
Schema.apply(this,arguments);
this.add({
key: String,
created_at: { type: Date, default: Date.now }
});
}
util.inherits(BaseSchema,Schema);
var metaSchema = new BaseSchema();
var stringSchema = new BaseSchema({
value: String
});
var numberSchema = new BaseSchema({
value: Number
});
var dateSchema = new BaseSchema({
value: Date
});
var MetaModel = mongoose.model('MetaModel',metaSchema),
StringModel = MetaModel.discriminator('StringModel', stringSchema),
NumberModel = MetaModel.discriminator('NumberModel', numberSchema),
DateModel = MetaModel.discriminator('DateModel', dateSchema);
async.series(
[
function(callback) {
MetaModel.remove({},callback);
},
function(callback) {
async.each(
[
{ "model": "StringModel", "value": "Hello" },
{ "model": "NumberModel", "value": 12 },
{ "model": "DateModel", "value": new Date() }
],
function(item,callback) {
mongoose.model(item.model).create(item,callback)
},
callback
);
},
function(callback) {
MetaModel.find().exec(function(err,docs) {
console.log(docs);
callback(err);
});
},
function(callback) {
DateModel.findOne().exec(function(err,doc) {
console.log(doc);
callback(err);
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
)
因此,这些基本上是相关的"我正在定义一个" Base"具有共同元素的模式。当然,每个"类型"都有单独的模式。实际分配给核心"模型"发生在以下几行:
var MetaModel = mongoose.model('MetaModel',metaSchema),
StringModel = MetaModel.discriminator('StringModel', stringSchema),
NumberModel = MetaModel.discriminator('NumberModel', numberSchema),
DateModel = MetaModel.discriminator('DateModel', dateSchema);
这意味着MetaModel
实际上定义了集合和"默认"模式分配。以下行使用该模型中的.discriminator()
来定义其他"类型"将存储在同一集合中的文件。
打开调试输出以显示正在发生的事情,列表产生如下内容:
Mongoose: metamodels.remove({}) {}
Mongoose: metamodels.insert({ value: 'Hello', __t: 'StringModel', created_at: new Date("Thu, 07 Apr 2016 00:24:08 GMT"), _id: ObjectId("5705a8a8443c0f74491bdec0"), __v: 0 })
Mongoose: metamodels.insert({ value: 12, __t: 'NumberModel', created_at: new Date("Thu, 07 Apr 2016 00:24:08 GMT"), _id: ObjectId("5705a8a8443c0f74491bdec1"), __v: 0 })
Mongoose: metamodels.insert({ value: new Date("Thu, 07 Apr 2016 00:24:08 GMT"), __t: 'DateModel', created_at: new Date("Thu, 07 Apr 2016 00:24:08 GMT"), _id: ObjectId("5705a8a8443c0f74491bdec2"), __v: 0 })
Mongoose: metamodels.find({}) { fields: undefined }
[ { created_at: Thu Apr 07 2016 10:24:08 GMT+1000 (AEST),
__t: 'StringModel',
__v: 0,
value: 'Hello',
_id: 5705a8a8443c0f74491bdec0 },
{ created_at: Thu Apr 07 2016 10:24:08 GMT+1000 (AEST),
__t: 'NumberModel',
__v: 0,
value: 12,
_id: 5705a8a8443c0f74491bdec1 },
{ created_at: Thu Apr 07 2016 10:24:08 GMT+1000 (AEST),
__t: 'DateModel',
__v: 0,
value: Thu Apr 07 2016 10:24:08 GMT+1000 (AEST),
_id: 5705a8a8443c0f74491bdec2 } ]
Mongoose: metamodels.findOne({ __t: 'DateModel' }) { fields: undefined }
{ created_at: Thu Apr 07 2016 10:24:08 GMT+1000 (AEST),
__t: 'DateModel',
__v: 0,
value: Thu Apr 07 2016 10:24:08 GMT+1000 (AEST),
_id: 5705a8a8443c0f74491bdec2 }
您可以看到在分配给主模型的metamodels
集合中创建了所有内容,但是在引用每个"鉴别器模型时#34;自动创建一个__t
字段,其中包含模型名称。这将在稍后用于读取数据时使用,因此mongoose知道在转换对象时应用哪个模型和附加模式。
当然,由于这些都有自己的架构,因此适用标准验证规则。此外,任何"实例方法"附加到每种类型的模式也适用于任何单独模型。
最后,__t
字段也适用于使用其中一个"鉴别器模型"用于任何其他操作,例如查询或更新。如上次执行的声明所示:
DateModel.findOne().exec(function(err,doc) {
console.log(doc);
callback(err);
});
和实际的电话:
Mongoose: metamodels.findOne({ __t: 'DateModel' }) { fields: undefined }
自动包含该属性值以指示"类型"并提供一个虚拟视图"收集数据就像它只包含那种特定类型一样。
真正的力量实际上在于同一集合中的所有对象以及猫鼬分配"类类型的能力"自动检索数据。