現在、ほぼ同じ2つのスキーマがあります。
var userSchema = mongoose.Schema({
email: {type: String, unique: true, required: true, validate: emailValidator},
passwordHash: {type: String, required: true},
firstname: {type: String, validate: firstnameValidator},
lastname: {type: String, validate: lastnameValidator},
phone: {type: String, validate: phoneValidator},
});
そして
var adminSchema = mongoose.Schema({
email: {type: String, unique: true, required: true, validate: emailValidator},
passwordHash: {type: String, required: true},
firstname: {type: String, validate: firstnameValidator, required: true},
lastname: {type: String, validate: lastnameValidator, required: true},
phone: {type: String, validate: phoneValidator, required: true},
});
唯一の違いは検証です。ユーザーは姓、名、電話を必要としません。ただし、管理者はこれらのプロパティを定義する必要があります。
残念ながら、上記のコードはほとんど同じなので、あまりドライではありません。したがって、adminSchema
に基づいてuserSchema
を構築できるかどうか疑問に思っています。例えば。:
var adminSchema = mongoose.Schema(userSchema);
adminSchema.change('firstname', {required: true});
adminSchema.change('lastname', {required: true});
adminSchema.change('phone', {required: true});
明らかにそれは単なる擬似コードです。このようなことは可能ですか?
別の非常に類似した質問は、別のスキーマに基づいて新しいスキーマを作成し、さらにいくつかのプロパティを追加することが可能かどうかです。例えば:
var adminSchema = mongoose.Schema(userSchema);
adminSchema.add(adminPower: Number);
他の場所にいる人もいます tils.inheritsを使用して推奨 スキーマを拡張します。別の簡単な方法は、次のように、設定を含むオブジェクトを設定し、そこからスキーマを作成することです。
_var settings = {
one: Number
};
new Schema(settings);
settings.two = Number;
new Schema(settings);
_
ただし、同じオブジェクトを変更しているので、少し見苦しいです。また、プラグインやメソッドなどを拡張できるようにしたいと考えています。したがって、私の推奨する方法は次のとおりです。
_function UserSchema (add) {
var schema = new Schema({
someField: String
});
if(add) {
schema.add(add);
}
return schema;
}
var userSchema = UserSchema();
var adminSchema = UserSchema({
anotherField: String
});
_
はい、あなたはadd()
fieldsという2番目の質問にたまたま答えます。したがって、スキーマの一部のプロパティを変更するには、上記の関数の変更バージョンが問題を解決します。
_function UserSchema (add, nameAndPhoneIsRequired) {
var schema = new Schema({
//...
firstname: {type: String, validate: firstnameValidator, required: nameAndPhoneIsRequired},
lastname: {type: String, validate: lastnameValidator, required: nameAndPhoneIsRequired},
phone: {type: String, validate: phoneValidator, required: nameAndPhoneIsRequired},
});
if(add) {
schema.add(add);
}
return schema;
}
_
Mongoose 3.8.1がDiscriminatorsをサポートするようになりました。ここからのサンプル: http://mongoosejs.com/docs/api.html#model_Model.discriminator
function BaseSchema() {
Schema.apply(this, arguments);
this.add({
name: String,
createdAt: Date
});
}
util.inherits(BaseSchema, Schema);
var PersonSchema = new BaseSchema();
var BossSchema = new BaseSchema({ department: String });
var Person = mongoose.model('Person', PersonSchema);
var Boss = Person.discriminator('Boss', BossSchema);
元のSchema#objを拡張できます。
const AdminSchema = new mongoose.Schema({}、Object.assign(UserSchema.obj、{...}))
例:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
email: {type: String, unique: true, required: true},
passwordHash: {type: String, required: true},
firstname: {type: String},
lastname: {type: String},
phone: {type: String}
});
// Extend function
const extend = (Schema, obj) => (
new mongoose.Schema(
Object.assign({}, Schema.obj, obj)
)
);
// Usage:
const AdminUserSchema = extend(UserSchema, {
firstname: {type: String, required: true},
lastname: {type: String, required: true},
phone: {type: String, required: true}
});
const User = mongoose.model('users', UserSchema);
const AdminUser = mongoose.model('admins', AdminUserSchema);
const john = new User({
email: '[email protected]',
passwordHash: 'bla-bla-bla',
firstname: 'John'
});
john.save();
const admin = new AdminUser({
email: '[email protected]',
passwordHash: 'bla-bla-bla',
firstname: 'Henry',
lastname: 'Hardcore',
// phone: '+555-5555-55'
});
admin.save();
// Oops! Error 'phone' is required
または、同じ方法でこのnpmモジュールを使用します。
const extendSchema = require('mongoose-extend-schema'); // not 'mongoose-schema-extend'
const UserSchema = new mongoose.Schema({
firstname: {type: String},
lastname: {type: String}
});
const ClientSchema = extendSchema(UserSchema, {
phone: {type: String, required: true}
});
Githubリポジトリを確認してください https://github.com/doasync/mongoose-extend-schema
mongoose-super npm module を公開しました。いくつかのテストを行いましたが、まだ実験段階です。仲間のアプリケーションでうまく機能するかどうか知りたいSO!
このモジュールは、親モデルと子スキーマ拡張に基づいて子Mongoose.jsモデルを返すinherit()コンビニエンス関数を提供します。また、親モデルのメソッドを呼び出すためのsuper()メソッドでモデルを拡張します。この機能を追加したのは、他の拡張/継承ライブラリでは見逃していたためです。
継承便利関数は、単純に discriminator method を使用します。
この説明に追加するには、mongoose.Schemaをカスタムの基本スキーマ定義でオーバーライドすることもできます。コードの互換性のために、new
なしでスキーマをインスタンス化できるようにするifステートメントを追加します。これは便利な場合もありますが、公開パッケージでこれを行う前によく考えてください。
var Schema = mongoose.Schema;
var BaseSyncSchema = function(obj, options) {
if (!(this instanceof BaseSyncSchema))
return new BaseSyncSchema(obj, options);
Schema.apply(this, arguments);
this.methods.update = function() {
this.updated = new Date();
};
this.add({
updated: Date
});
};
util.inherits(BaseSyncSchema, Schema);
// Edit!!!
// mongoose.Schema = BaseSyncSchema; <-- Does not work in mongoose 4
// Do this instead:
Object.defineProperty(mongoose, "Schema", {
value: BaseSyncSchema,
writable: false
});
これらのすべての答えは、スキーマに適用される拡張ヘルパー関数または拡張メソッドを使用するか、プラグイン/弁別子を使用するため、不必要に複雑に見えます。代わりに、シンプルでクリーンで操作しやすい次のソリューションを使用しました。ベーススキーマのブループリントを定義し、ブループリントを使用して実際のスキーマを構築します。
foo.blueprint.js
module.exports = {
schema: {
foo: String,
bar: Number,
},
methods: {
fooBar() {
return 42;
},
}
};
foo.schema.js
const {schema, methods} = require('./foo.blueprint');
const {Schema} = require('mongoose');
const FooSchema = new Schema(foo);
Object.assign(FooSchema.methods, methods);
module.exports = FooSchema;
bar.schema.js
const {schema, methods} = require('./foo.blueprint');
const {Schema} = require('mongoose');
const BarSchema = new Schema(Object.assign({}, schema, {
bar: String,
baz: Boolean,
}));
Object.assign(BarSchema.methods, methods);
module.exports = BarSchema;
元のスキーマのブループリントをそのまま使用し、Object.assign
同じオブジェクトを変更せずに、他のスキーマ用に好きな方法でブループリントを拡張できます。
スキーマ定義とオプションスキーマオプションを受け入れるスキーマファクトリ関数を作成し、渡されたスキーマ定義とオプションを、スキーマ間で共有するスキーマフィールドとオプションとマージすることができます。これを示す例(フィールドemail
とis_verified
、およびtimestamps
オプションが有効になっているスキーマを共有または拡張する場合):
// schemaFactory.js
const mongoose = require('mongoose');
const SchemaFactory = (schemaDefinition, schemaOptions) => {
return new mongoose.Schema({
{
email: {type: String, required: true},
is_verified: {type: Boolean, default: false},
// spread/merge passed in schema definition
...schemaDefinition
}
}, {
timestamps: true,
// spread/merge passed in schema options
...schemaOptions
})
}
module.exports = SchemaFactory;
SchemaFactory
関数は、次のようにして呼び出すことができます。
// schemas.js
const SchemaFactory = require("./schemaFactory.js")
const UserSchema = SchemaFactory({
first_name: String,
password: {type: String, required: true}
});
const AdminSchema = SchemaFactory({
role: {type: String, required: true}
}, {
// we can pass in schema options to the Schema Factory
strict: false
});
これで、UserSchema
とAdminSchema
にはemail
とis_verified
の両方のフィールドが含まれ、スキーマとともにtimestamps
オプションが有効になります渡すフィールドとオプション。
Mongooseスキーマを拡張する最も簡単な方法
import { model, Schema } from 'mongoose';
const ParentSchema = new Schema({
fromParent: Boolean
});
const ChildSchema = new Schema({
...ParentSchema.obj,
fromChild: Boolean // new properties come up here
});
export const Child = model('Child', ChildSchema);
とにかく親ドキュメントの一部として保存されているサブドキュメントスキーマを拡張しようとしていたので、区別する必要はありませんでした。
私の解決策は、ベーススキーマであるスキーマに「拡張」メソッドを追加することでした。これにより、ベーススキーマ自体を使用するか、ベーススキーマに基づいて新しいスキーマを生成できます。
ES6コードは次のとおりです。
'use strict';
//Dependencies
let Schema = require('mongoose').Schema;
//Schema generator
function extendFooSchema(fields, _id = false) {
//Extend default fields with given fields
fields = Object.assign({
foo: String,
bar: String,
}, fields || {});
//Create schema
let FooSchema = new Schema(fields, {_id});
//Add methods/options and whatnot
FooSchema.methods.bar = function() { ... };
//Return
return FooSchema;
}
//Create the base schema now
let FooSchema = extendFooSchema(null, false);
//Expose generator method
FooSchema.extend = extendFooSchema;
//Export schema
module.exports = FooSchema;
このスキーマをそのまま使用するか、必要に応じて「拡張」できます。
let BazSchema = FooSchema.extend({baz: Number});
この場合の拡張は、まったく新しいスキーマ定義を作成します。