SchemaTypes

SchemaTypes 处理路径 defaultsvalidationgetterssetters字段选择默认值queries 的定义,以及 Mongoose 文档属性的其他一般特性。

¥SchemaTypes handle definition of path defaults, validation, getters, setters, field selection defaults for queries, and other general characteristics for Mongoose document properties.

什么是 SchemaType?

¥What is a SchemaType?

你可以将 Mongoose 结构视为 Mongoose 模型的配置对象。SchemaType 是单个属性的配置对象。SchemaType 说明给定路径应具有什么类型、是否有任何 getter/setter 以及哪些值对该路径有效。

¥You can think of a Mongoose schema as the configuration object for a Mongoose model. A SchemaType is then a configuration object for an individual property. A SchemaType says what type a given path should have, whether it has any getters/setters, and what values are valid for that path.

const schema = new Schema({ name: String });
schema.path('name') instanceof mongoose.SchemaType; // true
schema.path('name') instanceof mongoose.Schema.Types.String; // true
schema.path('name').instance; // 'String'

SchemaType 与类型不同。换句话说,mongoose.ObjectId !== mongoose.Types.ObjectId。SchemaType 只是 Mongoose 的一个配置对象。mongoose.ObjectId SchemaType 的实例实际上并不创建 MongoDB ObjectId,它只是结构中路径的配置。

¥A SchemaType is different from a type. In other words, mongoose.ObjectId !== mongoose.Types.ObjectId. A SchemaType is just a configuration object for Mongoose. An instance of the mongoose.ObjectId SchemaType doesn't actually create MongoDB ObjectIds, it is just a configuration for a path in a schema.

以下是 Mongoose 中所有有效的 SchemaType。Mongoose 插件还可以添加自定义 SchemaType,例如 int32。查看 Mongoose 的插件搜索 来查找插件。

¥The following are all the valid SchemaTypes in Mongoose. Mongoose plugins can also add custom SchemaTypes like int32. Check out Mongoose's plugins search to find plugins.

示例

¥Example

const schema = new Schema({
  name: String,
  binary: Buffer,
  living: Boolean,
  updated: { type: Date, default: Date.now },
  age: { type: Number, min: 18, max: 65 },
  mixed: Schema.Types.Mixed,
  _someId: Schema.Types.ObjectId,
  decimal: Schema.Types.Decimal128,
  double: Schema.Types.Double,
  int32bit: Schema.Types.Int32,
  array: [],
  ofString: [String],
  ofNumber: [Number],
  ofDates: [Date],
  ofBuffer: [Buffer],
  ofBoolean: [Boolean],
  ofMixed: [Schema.Types.Mixed],
  ofObjectId: [Schema.Types.ObjectId],
  ofArrays: [[]],
  ofArrayOfNumbers: [[Number]],
  nested: {
    stuff: { type: String, lowercase: true, trim: true }
  },
  map: Map,
  mapOfString: {
    type: Map,
    of: String
  }
});

// example use

const Thing = mongoose.model('Thing', schema);

const m = new Thing;
m.name = 'Statue of Liberty';
m.age = 125;
m.updated = new Date;
m.binary = Buffer.alloc(0);
m.living = false;
m.mixed = { any: { thing: 'i want' } };
m.markModified('mixed');
m._someId = new mongoose.Types.ObjectId;
m.array.push(1);
m.ofString.push('strings!');
m.ofNumber.unshift(1, 2, 3, 4);
m.ofDates.addToSet(new Date);
m.ofBuffer.pop();
m.ofMixed = [1, [], 'three', { four: 5 }];
m.nested.stuff = 'good';
m.map = new Map([['key', 'value']]);
m.save(callback);

type

¥The type Key

type 是 Mongoose 结构中的一个特殊属性。当 Mongoose 在你的结构中找到名为 type 的嵌套属性时,Mongoose 假定它需要使用给定类型定义 SchemaType。

¥type is a special property in Mongoose schemas. When Mongoose finds a nested property named type in your schema, Mongoose assumes that it needs to define a SchemaType with the given type.

// 3 string SchemaTypes: 'name', 'nested.firstName', 'nested.lastName'
const schema = new Schema({
  name: { type: String },
  nested: {
    firstName: { type: String },
    lastName: { type: String }
  }
});

结果,你需要一些额外的工作来在结构中定义名为 type 的属性。例如,假设你正在构建一个股票档案应用,并且你想要存储资源的 type(股票、债券、ETF 等)。天真地,你可以定义你的结构,如下所示:

¥As a consequence, you need a little extra work to define a property named type in your schema. For example, suppose you're building a stock portfolio app, and you want to store the asset's type (stock, bond, ETF, etc.). Naively, you might define your schema as shown below:

const holdingSchema = new Schema({
  // You might expect `asset` to be an object that has 2 properties,
  // but unfortunately `type` is special in Mongoose so mongoose
  // interprets this schema to mean that `asset` is a string
  asset: {
    type: String,
    ticker: String
  }
});

但是,当 Mongoose 看到 type: String 时,它会假设你的意思是 asset 应该是一个字符串,而不是具有属性 type 的对象。定义具有属性 type 的对象的正确方法如下所示。

¥However, when Mongoose sees type: String, it assumes that you mean asset should be a string, not an object with a property type. The correct way to define an object with a property type is shown below.

const holdingSchema = new Schema({
  asset: {
    // Workaround to make sure Mongoose knows `asset` is an object
    // and `asset.type` is a string, rather than thinking `asset`
    // is a string.
    type: { type: String },
    ticker: String
  }
});

模式类型选项

¥SchemaType Options

你可以直接使用类型来声明结构类型,也可以使用具有 type 属性的对象来声明结构类型。

¥You can declare a schema type using the type directly, or an object with a type property.

const schema1 = new Schema({
  test: String // `test` is a path of type String
});

const schema2 = new Schema({
  // The `test` object contains the "SchemaType options"
  test: { type: String } // `test` is a path of type string
});

除了类型属性之外,你还可以为路径指定其他属性。例如,如果你想在保存之前将字符串小写:

¥In addition to the type property, you can specify additional properties for a path. For example, if you want to lowercase a string before saving:

const schema2 = new Schema({
  test: {
    type: String,
    lowercase: true // Always convert `test` to lowercase
  }
});

你可以将任何想要的属性添加到 SchemaType 选项中。许多插件依赖于自定义 SchemaType 选项。例如,如果你在 SchemaType 选项中设置 autopopulate: true,则 mongoose-autopopulate 插件会自动填充路径。Mongoose 支持多个内置 SchemaType 选项,例如上面示例中的 lowercase

¥You can add any property you want to your SchemaType options. Many plugins rely on custom SchemaType options. For example, the mongoose-autopopulate plugin automatically populates paths if you set autopopulate: true in your SchemaType options. Mongoose comes with support for several built-in SchemaType options, like lowercase in the above example.

lowercase 选项仅适用于字符串。有些选项适用于所有结构类型,有些选项适用于特定结构类型。

¥The lowercase option only works for strings. There are certain options which apply for all schema types, and some that apply for specific schema types.

所有结构类型

¥All Schema Types

  • required:布尔值或函数,如果为 true,则为此属性添加 所需的验证器

    ¥required: boolean or function, if true adds a required validator for this property

  • default:Any 或 函数,设置路径的默认值。如果该值是一个函数,则该函数的返回值将用作默认值。

    ¥default: Any or function, sets a default value for the path. If the value is a function, the return value of the function is used as the default.

  • select:布尔值,指定查询的默认 projections

    ¥select: boolean, specifies default projections for queries

  • validate:函数,为此属性添加 验证器功能

    ¥validate: function, adds a validator function for this property

  • get:函数,使用 Object.defineProperty(). 为该属性定义一个自定义 getter。

    ¥get: function, defines a custom getter for this property using Object.defineProperty().

  • set:函数,使用 Object.defineProperty().函数为此属性定义一个自定义设置器。

    ¥set: function, defines a custom setter for this property using Object.defineProperty().

  • alias:字符串,仅限 mongoose >= 4.10.0。使用给定名称定义获取/设置此路径的 virtual

    ¥alias: string, mongoose >= 4.10.0 only. Defines a virtual with the given name that gets/sets this path.

  • immutable:布尔值,将路径定义为不可变。Mongoose 会阻止你更改不可变路径,除非父文档具有 isNew: true

    ¥immutable: boolean, defines path as immutable. Mongoose prevents you from changing immutable paths unless the parent document has isNew: true.

  • transform:函数,Mongoose 在调用 Document#toJSON() 函数时调用该函数,包括当你 JSON.stringify() 一个文档时。

    ¥transform: function, Mongoose calls this function when you call Document#toJSON() function, including when you JSON.stringify() a document.

const numberSchema = new Schema({
  integerOnly: {
    type: Number,
    get: v => Math.round(v),
    set: v => Math.round(v),
    alias: 'i'
  }
});

const Number = mongoose.model('Number', numberSchema);

const doc = new Number();
doc.integerOnly = 2.001;
doc.integerOnly; // 2
doc.i; // 2
doc.i = 3.001;
doc.integerOnly; // 3
doc.i; // 3

索引

¥Indexes

你还可以使用结构类型选项定义 MongoDB 索引

¥You can also define MongoDB indexes using schema type options.

  • index:布尔值,是否在此属性上定义 index

    ¥index: boolean, whether to define an index on this property.

  • unique:布尔值,是否在此属性上定义 唯一索引

    ¥unique: boolean, whether to define a unique index on this property.

  • sparse:布尔值,是否在此属性上定义 稀疏索引

    ¥sparse: boolean, whether to define a sparse index on this property.

const schema2 = new Schema({
  test: {
    type: String,
    index: true,
    unique: true // Unique index. If you specify `unique: true`
    // specifying `index: true` is optional if you do `unique: true`
  }
});

字符串

¥String

  • lowercase:布尔值,是否始终对该值调用 .toLowerCase()

    ¥lowercase: boolean, whether to always call .toLowerCase() on the value

  • uppercase:布尔值,是否始终对该值调用 .toUpperCase()

    ¥uppercase: boolean, whether to always call .toUpperCase() on the value

  • trim:布尔值,是否始终对该值调用 .trim()

    ¥trim: boolean, whether to always call .trim() on the value

  • match:RegExp,创建一个 validator,检查该值是否与给定的正则表达式匹配

    ¥match: RegExp, creates a validator that checks if the value matches the given regular expression

  • enum:数组,创建一个 validator 来检查该值是否在给定数组中。

    ¥enum: Array, creates a validator that checks if the value is in the given array.

  • minLength:Number,创建一个 validator,检查值长度是否不小于给定数字

    ¥minLength: Number, creates a validator that checks if the value length is not less than the given number

  • maxLength:Number,创建一个 validator,检查值长度是否不大于给定数字

    ¥maxLength: Number, creates a validator that checks if the value length is not greater than the given number

  • populate:对象,设置默认 填充选项

    ¥populate: Object, sets default populate options

数字

¥Number

  • min:Number,创建一个 validator,检查该值是否大于或等于给定的最小值。

    ¥min: Number, creates a validator that checks if the value is greater than or equal to the given minimum.

  • max:Number,创建一个 validator,检查该值是否小于或等于给定的最大值。

    ¥max: Number, creates a validator that checks if the value is less than or equal to the given maximum.

  • enum:数组,创建一个 validator,检查该值是否严格等于给定数组中的值之一。

    ¥enum: Array, creates a validator that checks if the value is strictly equal to one of the values in the given array.

  • populate:对象,设置默认 填充选项

    ¥populate: Object, sets default populate options

日期

¥Date

  • min:日期,创建一个 validator,检查该值是否大于或等于给定的最小值。

    ¥min: Date, creates a validator that checks if the value is greater than or equal to the given minimum.

  • max:日期,创建一个 validator,检查该值是否小于或等于给定的最大值。

    ¥max: Date, creates a validator that checks if the value is less than or equal to the given maximum.

  • expires:数字或字符串,创建一个 TTL 索引,其值以秒为单位表示。

    ¥expires: Number or String, creates a TTL index with the value expressed in seconds.

ObjectId

使用说明

¥Usage Notes

字符串

¥String

要将路径声明为字符串,你可以使用 String 全局构造函数或字符串 'String'

¥To declare a path as a string, you may use either the String global constructor or the string 'String'.

const schema1 = new Schema({ name: String }); // name will be cast to string
const schema2 = new Schema({ name: 'String' }); // Equivalent

const Person = mongoose.model('Person', schema2);

如果传递一个具有 toString() 函数的元素,Mongoose 将调用它,除非该元素是数组或 toString() 函数严格等于 Object.prototype.toString()

¥If you pass an element that has a toString() function, Mongoose will call it, unless the element is an array or the toString() function is strictly equal to Object.prototype.toString().

new Person({ name: 42 }).name; // "42" as a string
new Person({ name: { toString: () => 42 } }).name; // "42" as a string

// "undefined", will get a cast error if you `save()` this document
new Person({ name: { foo: 42 } }).name;

数字

¥Number

要将路径声明为数字,你可以使用 Number 全局构造函数或字符串 'Number'

¥To declare a path as a number, you may use either the Number global constructor or the string 'Number'.

const schema1 = new Schema({ age: Number }); // age will be cast to a Number
const schema2 = new Schema({ age: 'Number' }); // Equivalent

const Car = mongoose.model('Car', schema2);

有几种类型的值可以成功转换为数字。

¥There are several types of values that will be successfully cast to a Number.

new Car({ age: '15' }).age; // 15 as a Number
new Car({ age: true }).age; // 1 as a Number
new Car({ age: false }).age; // 0 as a Number
new Car({ age: { valueOf: () => 83 } }).age; // 83 as a Number

如果你传递一个带有返回数字的 valueOf() 函数的对象,Mongoose 将调用它并将返回值分配给路径。

¥If you pass an object with a valueOf() function that returns a Number, Mongoose will call it and assign the returned value to the path.

nullundefined 不进行强制转换。

¥The values null and undefined are not cast.

NaN、转换为 NaN 的字符串、数组和没有 valueOf() 函数的对象在验证后都会生成 CastError,这意味着它不会在初始化时抛出,只有在验证时才会抛出。

¥NaN, strings that cast to NaN, arrays, and objects that don't have a valueOf() function will all result in a CastError once validated, meaning that it will not throw on initialization, only when validated.

日期

¥Dates

内置 Date 方法没有陷入 mongoose 更改跟踪逻辑,这在英文中意味着如果你在文档中使用 Date 并使用 setMonth() 之类的方法对其进行修改,mongoose 将不知道此更改,并且 doc.save() 不会保留此修改。如果必须使用内置方法修改 Date 类型,请在保存之前用 doc.markModified('pathToYourDate') 告诉 mongoose 所做的更改。

¥Built-in Date methods are not hooked into the mongoose change tracking logic which in English means that if you use a Date in your document and modify it with a method like setMonth(), mongoose will be unaware of this change and doc.save() will not persist this modification. If you must modify Date types using built-in methods, tell mongoose about the change with doc.markModified('pathToYourDate') before saving.

const Assignment = mongoose.model('Assignment', { dueDate: Date });
const doc = await Assignment.findOne();
doc.dueDate.setMonth(3);
await doc.save(); // THIS DOES NOT SAVE YOUR CHANGE

doc.markModified('dueDate');
await doc.save(); // works

缓冲

¥Buffer

要将路径声明为 Buffer,你可以使用 Buffer 全局构造函数或字符串 'Buffer'

¥To declare a path as a Buffer, you may use either the Buffer global constructor or the string 'Buffer'.

const schema1 = new Schema({ binData: Buffer }); // binData will be cast to a Buffer
const schema2 = new Schema({ binData: 'Buffer' }); // Equivalent

const Data = mongoose.model('Data', schema2);

Mongoose 将成功地将以下值投射到缓冲区。

¥Mongoose will successfully cast the below values to buffers.

const file1 = new Data({ binData: 'test'}); // {"type":"Buffer","data":[116,101,115,116]}
const file2 = new Data({ binData: 72987 }); // {"type":"Buffer","data":[27]}
const file4 = new Data({ binData: { type: 'Buffer', data: [1, 2, 3]}}); // {"type":"Buffer","data":[1,2,3]}

混合

¥Mixed

"什么都可以" 结构类型。Mongoose 不会在混合路径上进行任何投射。你可以使用 Schema.Types.Mixed 或传递空对象字面量来定义混合路径。以下是等效的。

¥An "anything goes" SchemaType. Mongoose will not do any casting on mixed paths. You can define a mixed path using Schema.Types.Mixed or by passing an empty object literal. The following are equivalent.

const Any = new Schema({ any: {} });
const Any = new Schema({ any: Object });
const Any = new Schema({ any: Schema.Types.Mixed });
const Any = new Schema({ any: mongoose.Mixed });

由于 Mixed 是无结构类型,因此你可以将值更改为你喜欢的任何其他值,但 Mongoose 失去了自动检测和保存这些更改的能力。要告诉 Mongoose Mixed 类型的值已更改,你需要调用 doc.markModified(path),将路径传递给刚刚更改的 Mixed 类型。

¥Since Mixed is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect and save those changes. To tell Mongoose that the value of a Mixed type has changed, you need to call doc.markModified(path), passing the path to the Mixed type you just changed.

为了避免这些副作用,可以改用 子文档 路径。

¥To avoid these side-effects, a Subdocument path may be used instead.

person.anything = { x: [3, 4, { y: 'changed' }] };
person.markModified('anything');
person.save(); // Mongoose will save changes to `anything`.

ObjectIds

ObjectId 是一种特殊类型,通常用于唯一标识符。以下是如何声明具有作为 ObjectId 的路径 driver 的结构:

¥An ObjectId is a special type typically used for unique identifiers. Here's how you declare a schema with a path driver that is an ObjectId:

const mongoose = require('mongoose');
const carSchema = new mongoose.Schema({ driver: mongoose.ObjectId });

ObjectId 是一个类,ObjectIds 是对象。但是,它们通常表示为字符串。当你使用 toString() 将 ObjectId 转换为字符串时,你会得到一个 24 个字符的十六进制字符串:

¥ObjectId is a class, and ObjectIds are objects. However, they are often represented as strings. When you convert an ObjectId to a string using toString(), you get a 24-character hexadecimal string:

const Car = mongoose.model('Car', carSchema);

const car = new Car();
car.driver = new mongoose.Types.ObjectId();

typeof car.driver; // 'object'
car.driver instanceof mongoose.Types.ObjectId; // true

car.driver.toString(); // Something like "5e1a0651741b255ddda996c4"

布尔值

¥Boolean

Mongoose 中的布尔值是 纯 JavaScript 布尔值。默认情况下,Mongoose 将以下值转换为 true

¥Booleans in Mongoose are plain JavaScript booleans. By default, Mongoose casts the below values to true:

  • true

  • 'true'

  • 1

  • '1'

  • 'yes'

Mongoose 将以下值转换为 false

¥Mongoose casts the below values to false:

  • false

  • 'false'

  • 0

  • '0'

  • 'no'

任何其他值都会导致 CastError。你可以使用 convertToTrueconvertToFalse 属性(即 JavaScript 集)修改 Mongoose 将哪些值转换为 true 或 false。

¥Any other value causes a CastError. You can modify what values Mongoose converts to true or false using the convertToTrue and convertToFalse properties, which are JavaScript sets.

const M = mongoose.model('Test', new Schema({ b: Boolean }));
console.log(new M({ b: 'nay' }).b); // undefined

// Set { false, 'false', 0, '0', 'no' }
console.log(mongoose.Schema.Types.Boolean.convertToFalse);

mongoose.Schema.Types.Boolean.convertToFalse.add('nay');
console.log(new M({ b: 'nay' }).b); // false

数组

¥Arrays

Mongoose 支持 SchemaTypes 数组和 subdocuments 数组。SchemaType 数组也称为原始数组,子文档数组也称为文档数组。

¥Mongoose supports arrays of SchemaTypes and arrays of subdocuments. Arrays of SchemaTypes are also called primitive arrays, and arrays of subdocuments are also called document arrays.

const ToySchema = new Schema({ name: String });
const ToyBoxSchema = new Schema({
  toys: [ToySchema],
  buffers: [Buffer],
  strings: [String],
  numbers: [Number]
  // ... etc
});

数组很特殊,因为它们隐式具有默认值 [](空数组)。

¥Arrays are special because they implicitly have a default value of [] (empty array).

const ToyBox = mongoose.model('ToyBox', ToyBoxSchema);
console.log((new ToyBox()).toys); // []

要覆盖此默认值,你需要将默认值设置为 undefined

¥To overwrite this default, you need to set the default value to undefined

const ToyBoxSchema = new Schema({
  toys: {
    type: [ToySchema],
    default: undefined
  }
});

注意:指定空数组相当于 Mixed。以下均创建 Mixed 数组:

¥Note: specifying an empty array is equivalent to Mixed. The following all create arrays of Mixed:

const Empty1 = new Schema({ any: [] });
const Empty2 = new Schema({ any: Array });
const Empty3 = new Schema({ any: [Schema.Types.Mixed] });
const Empty4 = new Schema({ any: [{}] });

映射

¥Maps

MongooseMapJavaScript 的 Map 的子类。在这些文档中,我们将互换使用术语 'map' 和 MongooseMap。在 Mongoose 中,映射是你使用任意键创建嵌套文档的方式。

¥A MongooseMap is a subclass of JavaScript's Map class. In these docs, we'll use the terms 'map' and MongooseMap interchangeably. In Mongoose, maps are how you create a nested document with arbitrary keys.

注意:在 Mongoose Maps 中,键必须是字符串才能将文档存储在 MongoDB 中。

¥Note: In Mongoose Maps, keys must be strings in order to store the document in MongoDB.

const userSchema = new Schema({
  // `socialMediaHandles` is a map whose values are strings. A map's
  // keys are always strings. You specify the type of values using `of`.
  socialMediaHandles: {
    type: Map,
    of: String
  }
});

const User = mongoose.model('User', userSchema);
// Map { 'github' => 'vkarpov15', 'twitter' => '@code_barbarian' }
console.log(new User({
  socialMediaHandles: {
    github: 'vkarpov15',
    twitter: '@code_barbarian'
  }
}).socialMediaHandles);

上面的示例没有显式地将 githubtwitter 声明为路径,但是,由于 socialMediaHandles 是一个映射,因此你可以存储任意键/值对。但是,由于 socialMediaHandles 是一个映射,因此必须使用 .get() 来获取键的值,并使用 .set() 来设置键的值。

¥The above example doesn't explicitly declare github or twitter as paths, but, since socialMediaHandles is a map, you can store arbitrary key/value pairs. However, since socialMediaHandles is a map, you must use .get() to get the value of a key and .set() to set the value of a key.

const user = new User({
  socialMediaHandles: {}
});

// Good
user.socialMediaHandles.set('github', 'vkarpov15');
// Works too
user.set('socialMediaHandles.twitter', '@code_barbarian');
// Bad, the `myspace` property will **not** get saved
user.socialMediaHandles.myspace = 'fail';

// 'vkarpov15'
console.log(user.socialMediaHandles.get('github'));
// '@code_barbarian'
console.log(user.get('socialMediaHandles.twitter'));
// undefined
user.socialMediaHandles.github;

// Will only save the 'github' and 'twitter' properties
user.save();

映射类型存储为 MongoDB 中的 BSON 对象。BSON 对象中的键是有序的,因此这意味着映射的 插入顺序 属性得到维护。

¥Map types are stored as BSON objects in MongoDB. Keys in a BSON object are ordered, so this means the insertion order property of maps is maintained.

Mongoose 支持特殊的 $* 语法来 populate 映射中的所有元素。例如,假设你的 socialMediaHandles 映射包含 ref

¥Mongoose supports a special $* syntax to populate all elements in a map. For example, suppose your socialMediaHandles map contains a ref:

const userSchema = new Schema({
  socialMediaHandles: {
    type: Map,
    of: new Schema({
      handle: String,
      oauth: {
        type: ObjectId,
        ref: 'OAuth'
      }
    })
  }
});
const User = mongoose.model('User', userSchema);

要填充每个 socialMediaHandles 条目的 oauth 属性,你应该填充 socialMediaHandles.$*.oauth

¥To populate every socialMediaHandles entry's oauth property, you should populate on socialMediaHandles.$*.oauth:

const user = await User.findOne().populate('socialMediaHandles.$*.oauth');

UUID

Mongoose 还支持将 UUID 实例存储为 Node.js 缓冲区 的 UUID 类型。我们建议在 Mongoose 中使用 ObjectIds 而不是 UUID 作为唯一文档 ID,但如果需要,你也可以使用 UUID。

¥Mongoose also supports a UUID type that stores UUID instances as Node.js buffers. We recommend using ObjectIds rather than UUIDs for unique document ids in Mongoose, but you may use UUIDs if you need to.

在 Node.js 中,UUID 表示为 bson.Binary 类型的实例,其中 getter 会在你访问它时将二进制文件转换为字符串。Mongoose 将 UUID 存储为 MongoDB 中子类型 4 的二进制数据

¥In Node.js, a UUID is represented as an instance of bson.Binary type with a getter that converts the binary to a string when you access it. Mongoose stores UUIDs as binary data with subtype 4 in MongoDB.

const authorSchema = new Schema({
  _id: Schema.Types.UUID, // Can also do `_id: 'UUID'`
  name: String
});

const Author = mongoose.model('Author', authorSchema);

const bookSchema = new Schema({
  authorId: { type: Schema.Types.UUID, ref: 'Author' }
});
const Book = mongoose.model('Book', bookSchema);

const author = new Author({ name: 'Martin Fowler' });
console.log(typeof author._id); // 'string'
console.log(author.toObject()._id instanceof mongoose.mongo.BSON.Binary); // true

const book = new Book({ authorId: '09190f70-3d30-11e5-8814-0f4df9a59c41' });

要创建 UUID,我们建议使用 Node 的内置 UUIDv4 生成器

¥To create UUIDs, we recommend using Node's built-in UUIDv4 generator.

const { randomUUID } = require('crypto');

const schema = new mongoose.Schema({
  docId: {
    type: 'UUID',
    default: () => randomUUID()
  }
});

BigInt

Mongoose 支持 JavaScript 大整数 作为 SchemaType。BigInt 存储为 MongoDB 中的 64 位整数(BSON 类型 "long")

¥Mongoose supports JavaScript BigInts as a SchemaType. BigInts are stored as 64-bit integers in MongoDB (BSON type "long").

const questionSchema = new Schema({
  answer: BigInt
});
const Question = mongoose.model('Question', questionSchema);

const question = new Question({ answer: 42n });
typeof question.answer; // 'bigint'

Double

Mongoose 支持 64 位 IEEE 754-2008 浮点数 作为 SchemaType。Int32 存储为 MongoDB 中的 BSON 类型 "double"

¥Mongoose supports 64-bit IEEE 754-2008 floating point numbers as a SchemaType. Int32s are stored as BSON type "double" in MongoDB.

const studentsSchema = new Schema({
  id: Int32
});
const Student = mongoose.model('Student', schema);

const student = new Temperature({ celsius: 1339 });
typeof student.id; // 'number'

有几种类型的值将成功转换为 Double。

¥There are several types of values that will be successfully cast to a Double.

new Temperature({ celsius: '1.2e12' }).celsius; // 15 as a Double
new Temperature({ celsius: true }).celsius; // 1 as a Double
new Temperature({ celsius: false }).celsius; // 0 as a Double
new Temperature({ celsius: { valueOf: () => 83.0033 } }).celsius; // 83 as a Double
new Temperature({ celsius: '' }).celsius; // null as a Double

以下输入一旦验证将全部导致 CastError,这意味着它不会在初始化时抛出,只有在验证时才会抛出:

¥The following inputs will result will all result in a CastError once validated, meaning that it will not throw on initialization, only when validated:

  • 不表示数字字符串、NaN 或空值的字符串

    ¥strings that do not represent a numeric string, a NaN or a null-ish value

  • 没有 valueOf() 函数的对象

    ¥objects that don't have a valueOf() function

  • 表示超出 IEEE 754-2008 浮点范围的值的输入

    ¥an input that represents a value outside the bounds of a IEEE 754-2008 floating point

Int32

Mongoose 支持 32 位整数作为 SchemaType。Int32 存储为 MongoDB 中的 32 位整数(BSON 类型 "int")

¥Mongoose supports 32-bit integers as a SchemaType. Int32s are stored as 32-bit integers in MongoDB (BSON type "int").

const studentsSchema = new Schema({
  id: Int32
});
const Student = mongoose.model('Student', schema);

const student = new Temperature({ celsius: 1339 });
typeof student.id; // 'number'

有几种类型的值可以成功转换为数字。

¥There are several types of values that will be successfully cast to a Number.

new Student({ id: '15' }).id; // 15 as a Int32
new Student({ id: true }).id; // 1 as a Int32
new Student({ id: false }).id; // 0 as a Int32
new Student({ id: { valueOf: () => 83 } }).id; // 83 as a Int32
new Student({ id: '' }).id; // null as a Int32

如果你传递一个带有返回数字的 valueOf() 函数的对象,Mongoose 将调用它并将返回值分配给路径。

¥If you pass an object with a valueOf() function that returns a Number, Mongoose will call it and assign the returned value to the path.

nullundefined 不进行强制转换。

¥The values null and undefined are not cast.

以下输入一旦验证将全部导致 CastError,这意味着它不会在初始化时抛出,只有在验证时才会抛出:

¥The following inputs will result will all result in a CastError once validated, meaning that it will not throw on initialization, only when validated:

  • NaN

  • 转换为 NaN 的字符串

    ¥strings that cast to NaN

  • 没有 valueOf() 函数的对象

    ¥objects that don't have a valueOf() function

  • 必须四舍五入为整数的小数

    ¥a decimal that must be rounded to be an integer

  • 表示超出 32 位整数范围的值的输入

    ¥an input that represents a value outside the bounds of an 32-bit integer

获取器

¥Getters

Getter 就像结构中定义的路径的虚拟变量。例如,假设你想要将用户个人资料图片存储为相对路径,然后在应用中添加主机名。以下是你如何构建 userSchema

¥Getters are like virtuals for paths defined in your schema. For example, let's say you wanted to store user profile pictures as relative paths and then add the hostname in your application. Below is how you would structure your userSchema:

const root = 'https://s3.amazonaws.com/mybucket';

const userSchema = new Schema({
  name: String,
  picture: {
    type: String,
    get: v => `${root}${v}`
  }
});

const User = mongoose.model('User', userSchema);

const doc = new User({ name: 'Val', picture: '/123.png' });
doc.picture; // 'https://s3.amazonaws.com/mybucket/123.png'
doc.toObject({ getters: false }).picture; // '/123.png'

通常,你仅在原始路径上使用 getter,而不是在数组或子文档上。由于 getter 会覆盖访问 Mongoose 路径返回的内容,因此在对象上声明 getter 可能会删除对该路径的 Mongoose 更改跟踪。

¥Generally, you only use getters on primitive paths as opposed to arrays or subdocuments. Because getters override what accessing a Mongoose path returns, declaring a getter on an object may remove Mongoose change tracking for that path.

const schema = new Schema({
  arr: [{ url: String }]
});

const root = 'https://s3.amazonaws.com/mybucket';

// Bad, don't do this!
schema.path('arr').get(v => {
  return v.map(el => Object.assign(el, { url: root + el.url }));
});

// Later
doc.arr.push({ key: String });
doc.arr[0]; // 'undefined' because every `doc.arr` creates a new array!

你应该在 url 字符串上声明 getter,而不是如上所示在数组上声明 getter,如下所示。如果你需要在嵌套文档或数组上声明 getter,请务必小心!

¥Instead of declaring a getter on the array as shown above, you should declare a getter on the url string as shown below. If you need to declare a getter on a nested document or array, be very careful!

const schema = new Schema({
  arr: [{ url: String }]
});

const root = 'https://s3.amazonaws.com/mybucket';

// Good, do this instead of declaring a getter on `arr`
schema.path('arr.0.url').get(v => `${root}${v}`);

结构

¥Schemas

要将路径声明为另一个 schema,请将 type 设置为子结构的实例。

¥To declare a path as another schema, set type to the sub-schema's instance.

要根据子结构的形状设置默认值,只需设置一个默认值,该值将根据子结构的定义进行转换,然后在文档创建期间进行设置。

¥To set a default value based on the sub-schema's shape, simply set a default value, and the value will be cast based on the sub-schema's definition before being set during document creation.

const subSchema = new mongoose.Schema({
  // some schema definition here
});

const schema = new mongoose.Schema({
  data: {
    type: subSchema,
    default: {}
  }
});

创建自定义类型

¥Creating Custom Types

Mongoose 也可以用 自定义结构类型 进行扩展。在 plugins 网站上搜索兼容类型,例如 mongoose-longmongoose-int32mongoose-function

¥Mongoose can also be extended with custom SchemaTypes. Search the plugins site for compatible types like mongoose-long, mongoose-int32, and mongoose-function.

阅读有关创建自定义 SchemaType 此处 的更多信息。

¥Read more about creating custom SchemaTypes here.

schema.path() 函数

¥The schema.path() Function

schema.path() 函数返回给定路径的实例化结构类型。

¥The schema.path() function returns the instantiated schema type for a given path.

const sampleSchema = new Schema({ name: { type: String, required: true } });
console.log(sampleSchema.path('name'));
// Output looks like:
/**

 * SchemaString {

 *   enumValues: [],

  *   regExp: null,

  *   path: 'name',

  *   instance: 'String',

  *   validators: ...
  */

你可以使用此函数检查给定路径的结构类型,包括它具有哪些验证器以及类型是什么。

¥You can use this function to inspect the schema type for a given path, including what validators it has and what the type is.

进一步阅读

¥Further Reading

下一步

¥Next Up

现在我们已经介绍了 SchemaTypes,让我们来看看 连接

¥Now that we've covered SchemaTypes, let's take a look at Connections.