简体   繁体   English

带有日期的猫鼬混合类型字段

[英]Mongoose Mixed type field with dates

I'm creating an app where a user can create various types of custom fields, and I'd like to store those fields in mongo. 我正在创建一个应用程序,用户可以在其中创建各种类型的自定义字段,并且希望将这些字段存储在mongo中。 The types will include String, Number, and Date. 类型包括字符串,数字和日期。 My schema looks like this: 我的架构如下所示:

const MetaSchema = new mongoose.Schema({
  key: String,
  value: {type: mongoose.Schema.Types.Mixed},
  type: String,
  created_at: {type: Date, default: Date.now}
});

This works great, and I can store my data as expected. 这很好用,我可以按预期存储数据。 The issue is, when I want to store a date for instance, that gets sent across to the server in ISO format, a payload that might look like: 问题是,例如,当我想存储一个日期时,该日期将以ISO格式发送到服务器,那么有效负载可能如下所示:

{
  "key": "Contract Signed",
  "value": "2016-04-06T22:35:11.540Z",
  "type": "date"
}

Any way I can get mongo / mongoose to treat and store this like a date instead of a string? 有什么办法可以让mongo / mongoose像日期一样对待和存储它,而不是字符串? If I set this to type date then I think it would do the trick, but I have to save just about anything they can come up with for custom fields. 如果我将其设置为键入date,那么我认为它可以解决问题,但是我必须保存他们可以为自定义字段提供的任何内容。 Thanks so much! 非常感谢!

TLDR: Can a mixed data type in mongoose / mongo be treated differently based on the type of data being inserted (IE Date vs String). TLDR:能否根据插入的数据类型(IE日期与字符串)对猫鼬/ mongo中的混合数据类型进行不同的处理。

Using mongoose discriminators is probably the way to go here. 使用猫鼬歧视者可能是这里的方法。 They actually work with their own "type" ( default __t but can be overridden ) property within the stored documents which allows mongoose to actually apply a kind of "model" to each object with it's own attached schema. 它们实际上在存储的文档中使用自己的“类型”(默认为__t但可以覆盖)属性,该属性允许猫鼬实际上将一种“模型”应用于具有其自身附加模式的每个对象。

As a brief example: 作为一个简单的例子:

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

So since these are basically "related" I am defining a "Base" schema with the common elements. 因此,由于这些基本上是“相关的”,因此我要定义具有公共元素的“基础”架构。 Then of course there are separate schemas for each "type". 当然,每个“类型”都有单独的架构。 The actual assignment to the core "model" happens in these lines: 对核心“模型”的实际分配发生在以下几行:

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

This means that MetaModel actually defines the collection and "default" schema assingment. 这意味着MetaModel实际上定义了集合和“默认”模式分配。 The following lines use .discriminator() from that model in order to define the other "types" of documents that will be stored in the same collection. 以下各行使用该模型中的.discriminator()来定义将存储在同一集合中的其他“类型”的文档。

With the debugging output on to show what is happening, the listing produces something like this: 在打开调试输出以显示正在发生的情况的情况下,清单产生如下内容:

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 }

You can see that everything is being created in the metamodels collection assigned to the main model, however when referencing each "discriminator model" there is a __t field automatically created that includes the model name. 您可以看到在分配给主模型的metamodels集合中正在创建所有内容,但是,在引用每个“鉴别器模型”时,会自动创建一个包含模型名称的__t字段。 This will be used later on reading the data back so mongoose knows which model and attached schema to apply when casting the objects. 稍后将在读取数据时使用它,以便猫鼬知道在投射对象时要应用哪种模型和附加模式。

Naturally since these all have their own schema, the standard validation rules apply. 自然,由于所有这些都有自己的架构,因此适用标准验证规则。 In addition any "instance methods" attached to the schema for each type also apply just as it would with any separate model. 此外,每种类型附加到架构的任何“实例方法”也适用,就像使用任何单独的模型一样。

Finally, that __t field is also applied with using one of the "discriminator models" for any other operation such as query or update. 最后,对于任何其他操作(例如查询或更新),都使用“歧视模型”之一来应用该__t字段。 As shown in the last executed statement: 如最后执行的语句所示:

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

And the actual call: 和实际的调用:

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

That property value is included automatically to indicate the "type" and give a "virtual view" of the collection data just as if it only contained that particular type. 该属性值会自动包含在内,以指示“类型”并给出收集数据的“虚拟视图”,就好像它仅包含该特定类型一样。

The real power actually lies in all objects being in the same collection and the ability of mongoose to assign the "class type" automatically on retrieval of data. 实际上,真正的力量在于所有对象都在同一个集合中,猫鼬具有在检索数据时自动分配“类类型”的能力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM