2013-08-19 2 views
15

В настоящее время у меня есть две почти одинаковые схемы:Mongoose: расширение схемы

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}, 

}); 

Их единственное отличие заключается в проверке: Пользователям не нужен Firstname, фамилия или телефон. Однако админы должны определять эти свойства.

К сожалению, приведенный выше код не очень СУХОЙ, так как он почти идентичен. Поэтому мне интересно, можно ли построить 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); 
+0

И люди alredy делают это https://github.com/briankircho/mongoose-schema-extend см. Это. – diproart

ответ

7

Некоторые люди имеют в других местах suggested using utils.inherits для расширения схем. Другой простой способ будет просто создать объект с параметрами и создать Schemas от него, например, так:

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() поля. Таким образом, чтобы изменить некоторые свойства схемы, модифицированная версия вышеуказанной функции может решить вашу проблему:

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; 
} 
+0

Спасибо. К сожалению, похоже, что все эти решения добавляют некоторую сложность. Даже первый из них приводит к ситуации, когда у нас теперь есть пользовательские настройки, userSchema и userModel. Будет ли использование.inherits более чистым подходом? Постскриптум Я думаю, что в вашем втором примере есть опечатка. Это должно быть 'var adminSchema = UserSchema() {..' – Tom

+0

[Этот поток] (https://groups.google.com/forum/#!topic/mongoose-orm/aeqGRRnpFvg) обсуждает такое наследование. Я не считаю его более чистым (это столько же кода, но уродливее), и некоторые люди упоминают, что он глючит. –

24

Mongoose 3.8.1 теперь поддерживает дискриминаторами. Образец, отсюда: 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); 
+1

И люди alredy делают это https://github.com/briankircho/mongoose-schema-extend см. Это. – diproart

+11

@ diproart Это немного устарело, но если вы читаете это в '15, не используйте мангуст-схему-расширение.Существует много проблем, и плагин не обновляется с 13. Пойдите для мангуста «Дискриминаторы», если вы не хотите испытывать проблемы ... – romualdr

+1

В настоящее время он активно поддерживается, но может быть хорошей идеей полагаться на дискриминаторы в любом случае –

2

Чтобы добавить к этому обсуждению, вы можете также переопределить mongoose.Schema с определением пользовательской базы схемы. Для совместимости кода добавьте оператор if, который позволяет создать экземпляр схемы без new. Хотя это может быть удобно, подумайте дважды, прежде чем делать это в публичном пакете.

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

Я только что опубликовал mongoose-super npm module. Хотя я и проводил некоторые испытания, он все еще находится на экспериментальной стадии. Мне интересно узнать, хорошо ли это работает для приложений моих пользователей SO!

Модуль предоставляет функцию удобства inherit(), которая возвращает дочернюю модель Mongoose.js на основе родительской модели и расширения дочерней схемы. Он также дополняет модели с помощью метода super() для вызова методов родительской модели. Я добавил эту функциональность, потому что это то, что я пропустил в других библиотеках расширения/наследования.

Функция удобства наследования просто использует discriminator method.

0

Я не требовал дискриминации, поскольку я пытался расширить схему вспомогательных документов, которые в любом случае хранятся как часть родительского документа.

Моим решением было добавить метод «расширения» к схеме, являющейся базовой схемой, чтобы вы могли либо использовать базовую схему, либо создать на ней новую схему.

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

Extension в этом случае создает совершенно новое определение схемы.

0

Вы можете продлить первоначальный схемы # OBJ:

Const AdminSchema = новый 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 

Или использовать этот модуль НПМ с такой же подход:

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

0

Все эти ответы кажутся весьма неоправданно сложным, с вспомогательными функциями расширения или расширить методы, применяемые к схеме, так и через плагины/дискриминаторы. Вместо этого я использовал следующее решение, которое просто, чисто и легко работать. Она определяет план для базовой схемы, а затем фактические схемы строятся с использованием план:

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; 

бар. 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 вы можете расширить схему любым способом, который вам нравится для других схем, без изменения одного и того же объекта.

Смежные вопросы