首页 文章

具有日期的猫鼬混合型字段

提问于
浏览
1

我正在创建一个用户可以创建各种类型的自定义字段的应用程序,我想将这些字段存储在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中的混合数据类型进行不同的处理 .

1 回答

  • 2

    使用mongoose discriminators可能就是这里的方法 . 它们实际上在存储的文档中使用它们自己的"type"(默认 __t 但可以被覆盖)属性,这允许mongoose实际将一种"model"应用于每个对象及其自己的附加模式 .

    作为一个简短的例子:

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

    因此,由于这些基本上是“相关的”,我正在定义具有共同元素的“基础”模式 . 当然,每种“类型”都有单独的模式 . 核心“模型”的实际分配发生在以下几行:

    var MetaModel = mongoose.model('MetaModel',metaSchema),
        StringModel = MetaModel.discriminator('StringModel', stringSchema),
        NumberModel = MetaModel.discriminator('NumberModel', numberSchema),
        DateModel = MetaModel.discriminator('DateModel', dateSchema);
    

    这意味着 MetaModel 实际上定义了集合和"default"模式分配 . 以下行使用该模型中的 .discriminator() 来定义将存储在同一集合中的其他"types"文档 .

    打开调试输出以显示正在发生的事情,列表产生如下所示:

    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 集合中创建了所有内容,但是在引用每个"discriminator model"时,会自动创建一个包含模型名称的 __t 字段 . 这将在稍后用于读取数据时使用,因此mongoose知道在转换对象时应用哪个模型和附加的模式 .

    当然,由于这些都有自己的架构,因此适用标准验证规则 . 此外,每种类型附加到模式的任何“实例方法”也适用于任何单独模型 .

    最后,对于任何其他操作(如查询或更新), __t 字段也应用于"discriminator models"之一 . 如上次执行的声明所示:

    DateModel.findOne().exec(function(err,doc) {
            console.log(doc);
            callback(err);
          });
    

    和实际的电话:

    Mongoose: metamodels.findOne({ __t: 'DateModel' }) { fields: undefined }
    

    自动包含该属性值以指示“类型”并给出集合数据的“虚拟视图”,就好像它仅包含该特定类型一样 .

    真正的力量实际上在于同一集合中的所有对象以及猫鼬在检索数据时自动分配“类类型”的能力 .

相关问题