2013-08-19 129 views
15

目前我有兩個幾乎相同的模式:貓鼬:擴展模式

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

}); 

他們唯一的區別是在驗證:用戶不需要名字,姓氏或電話。但管理員必須定義這些屬性。

不幸的是,上面的代碼不是非常乾燥,因爲它們幾乎完全相同。因此,我想知道是否有可能建立一個基於userSchemaadminSchema。例如:

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

而且人們還是這麼做https://github.com/briankircho/mongoose-schema-extend看到這個。 – diproart

回答

7

有些人在其他地方有suggested using utils.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()領域。因此,要修改架構的一些性質,上述功能的修改版本將解決你的問題:

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

謝謝。不幸的是,似乎所有這些解決方案增加了一些複雜性即使是第一個,我們現在有一個userSettings,一個userSchema和一個userModel。 util.inherits會是一個更清潔的方法嗎?附:我認爲你的第二個例子有一個錯字。它應該是'var adminSchema = UserSchema(){..' – Tom

+0

[This thread](https://groups.google.com/forum/#!topic/mongoose-orm/aeqGRRnpFvg)討論了這種繼承。我不覺得它更乾淨(它只是代碼,但更醜陋),有些人提到它是越野車。 –

24

貓鼬現在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

而且人們都會這樣做https://github.com/briankircho/mongoose-schema-extend看到這個。 – diproart

+11

@diproart這有點舊,但是如果你在15年閱讀這個,不要使用mongoose-schema-extend。有很多問題打開,插件自13年以來沒有更新。如果你不想遇到問題,去找貓鼬「鑑別者」...... – romualdr

+1

現在它已經得到了積極的維護,但是反正依靠辨別者可能是一個好主意 –

2

要加入討論,你也可以用自定義的基礎架構定義覆蓋mongoose.Schema。爲了兼容代碼,添加if語句,允許在沒有new的情況下實例化Schema。雖然這可能很方便,但在公開包裝中進行此操作之前請三思。

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

擴展在這種情況下,創造了一個全新的模式定義。

0

可以擴展原始架構#OBJ

常量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 

或者用如下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

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您可以以任何您喜歡的方式擴展藍圖,而無需修改相同的對象。