web-dev-qa-db-ja.com

Mongoose:スキーマの拡張

現在、ほぼ同じ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);
24
Tom

他の場所にいる人もいます 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;
}
_
11

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);
30
regretoverflow

元の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

8
Do Async

mongoose-super npm module を公開しました。いくつかのテストを行いましたが、まだ実験段階です。仲間のアプリケーションでうまく機能するかどうか知りたいSO!

このモジュールは、親モデルと子スキーマ拡張に基づいて子Mongoose.jsモデルを返すinherit()コンビニエンス関数を提供します。また、親モデルのメソッドを呼び出すためのsuper()メソッドでモデルを拡張します。この機能を追加したのは、他の拡張/継承ライブラリでは見逃していたためです。

継承便利関数は、単純に discriminator method を使用します。

2
Visionscaper

この説明に追加するには、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
});
2
Adam Lockhart

これらのすべての答えは、スキーマに適用される拡張ヘルパー関数または拡張メソッドを使用するか、プラグイン/弁別子を使用するため、不必要に複雑に見えます。代わりに、シンプルでクリーンで操作しやすい次のソリューションを使用しました。ベーススキーマのブループリントを定義し、ブループリントを使用して実際のスキーマを構築します。

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同じオブジェクトを変更せずに、他のスキーマ用に好きな方法でブループリントを拡張できます。

1
Adam Reis

スキーマ定義とオプションスキーマオプションを受け入れるスキーマファクトリ関数を作成し、渡されたスキーマ定義とオプションを、スキーマ間で共有するスキーマフィールドとオプションとマージすることができます。これを示す例(フィールドemailis_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
});

これで、UserSchemaAdminSchemaにはemailis_verifiedの両方のフィールドが含まれ、スキーマとともにtimestampsオプションが有効になります渡すフィールドとオプション。

0
darthchudi

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);
0
nakhodkiin

とにかく親ドキュメントの一部として保存されているサブドキュメントスキーマを拡張しようとしていたので、区別する必要はありませんでした。

私の解決策は、ベーススキーマであるスキーマに「拡張」メソッドを追加することでした。これにより、ベーススキーマ自体を使用するか、ベーススキーマに基づいて新しいスキーマを生成できます。

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

この場合の拡張は、まったく新しいスキーマ定義を作成します。

0
Adam Reis