2013-08-19 35 views
15

Hiện nay tôi có hai schemas gần như giống hệt nhau:Mongoose: mở rộng schemas

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

}); 

khác biệt duy nhất của họ là trong xác nhận: Người dùng không cần một firstname, lastname hoặc điện thoại. Tuy nhiên, quản trị viên phải có các thuộc tính này được xác định.

Thật không may mã trên không phải là rất khô, vì chúng gần như giống hệt nhau. Do đó, tôi tự hỏi liệu có thể xây dựng một số adminSchema dựa trên số userSchema hay không. Ví dụ:

var adminSchema = mongoose.Schema(userSchema); 
adminSchema.change('firstname', {required: true}); 
adminSchema.change('lastname', {required: true}); 
adminSchema.change('phone', {required: true}); 

Rõ ràng đó chỉ là mã giả. Có phải bất cư thứ gì như thế này đều được?

Một câu hỏi tương tự khác là nếu có thể tạo giản đồ mới dựa trên một lược đồ khác và thêm một số thuộc tính khác vào nó. Ví dụ:

var adminSchema = mongoose.Schema(userSchema); 
    adminSchema.add(adminPower: Number); 
+0

Và mọi người alredy làm điều đó https://github.com/briankircho/mongoose-schema-extend thấy điều này. – diproart

Trả lời

7

Một số người ở những nơi khác suggested using utils.inherits để mở rộng lược đồ. Một cách đơn giản có thể chỉ cần thiết lập một đối tượng với các thiết lập và tạo Schemas từ nó, như vậy:

var settings = { 
    one: Number 
}; 

new Schema(settings); 

settings.two = Number; 
new Schema(settings); 

Đó là một chút xấu xí tuy nhiên, kể từ khi bạn đang sửa đổi cùng một đối tượng. Ngoài ra tôi muốn để có thể mở rộng bổ sung và phương pháp vv Vì vậy phương pháp ưa thích của tôi là như sau:

function UserSchema (add) { 
    var schema = new Schema({ 
    someField: String 
    }); 

    if(add) { 
    schema.add(add); 
    } 

    return schema; 
} 

var userSchema = UserSchema(); 
var adminSchema = UserSchema({ 
    anotherField: String 
}); 

nào xảy ra để trả lời câu hỏi thứ hai của bạn mà có, bạn có thể add() lĩnh vực. Vì vậy, để sửa đổi một số thuộc tính của Lược đồ, một phiên bản sửa đổi của hàm trên sẽ giải quyết được vấn đề của bạn:

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

Cảm ơn. Thật không may có vẻ như tất cả các giải pháp này thêm một số phức tạp. Ngay cả kết quả đầu tiên trong một tình huống mà bây giờ chúng ta có một userSettings, một userSchema và một userModel. Liệu util.inherits có phải là một cách tiếp cận sạch hơn không? P.S. Tôi nghĩ rằng có một lỗi đánh máy trong ví dụ thứ hai của bạn. Nó phải là 'var adminSchema = UserSchema() {..' – Tom

+0

[Chủ đề này] (https://groups.google.com/forum/#!topic/mongoose-orm/aeqGRRnpFvg) thảo luận về kế thừa đó. Tôi không tìm thấy nó sạch hơn (nó chỉ là nhiều mã nhưng xấu xí hơn) và một số người đề cập đến nó là lỗi. –

24

Mongoose 3.8.1 hiện có hỗ trợ cho các nhà phân biệt đối xử. Một ví dụ, từ đây: 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

Và mọi người alredy làm điều đó https://github.com/briankircho/mongoose-schema-extend thấy điều này. – diproart

+11

@diproart Đó là một chút cũ, nhưng nếu bạn đang đọc này trong '15, không sử dụng mongoose-schema-extend.Đã có nhiều sự cố được mở và plugin chưa được cập nhật kể từ '13. Đi cho người chăn cừu "Discriminators" nếu bạn không muốn gặp vấn đề ... – romualdr

+1

Nó hiện đang được duy trì tích cực, nhưng nó có thể là một ý tưởng tốt để dựa vào phân biệt đối xử anyway –

2

Để thêm vào cuộc thảo luận này, bạn cũng có thể ghi đè lên mongoose.Schema với một định nghĩa giản đồ cơ sở tùy chỉnh. Để tương thích mã, hãy thêm câu lệnh if cho phép một Giản đồ được khởi tạo mà không cần new. Trong khi điều này có thể thuận tiện, hãy suy nghĩ kỹ trước khi thực hiện việc này trong gói công khai.

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

Tôi vừa xuất bản mongoose-super npm module. Mặc dù tôi đã làm một số thử nghiệm, nó vẫn còn trong giai đoạn thử nghiệm. Tôi quan tâm để biết nếu nó hoạt động tốt cho các ứng dụng của người dùng SO đồng nghiệp của tôi!

Mô-đun cung cấp một hàm thuận tiện kế thừa() trả về mô hình Mongoose.js con dựa trên mô hình cha và phần mở rộng giản đồ con. Nó cũng tăng thêm các mô hình với một phương thức super() để gọi các phương thức mô hình cha mẹ. Tôi đã thêm chức năng này bởi vì nó là thứ tôi đã bỏ lỡ trong các thư viện mở rộng/thừa kế khác.

Chức năng thuận tiện kế thừa chỉ đơn giản là sử dụng discriminator method.

0

Tôi không yêu cầu phân biệt đối xử, vì tôi đã cố mở rộng giản đồ tài liệu phụ được lưu trữ như một phần của tài liệu gốc.

Giải pháp của tôi là thêm một phương thức "mở rộng" vào lược đồ là lược đồ cơ sở, để bạn có thể sử dụng chính lược đồ cơ sở hoặc tạo lược đồ mới dựa trên nó.

ES6 đang sau:

'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; 

Bây giờ bạn có thể sử dụng sơ đồ này như là, hoặc "mở rộng" nó khi cần thiết:

let BazSchema = FooSchema.extend({baz: Number}); 

mở rộng trong trường hợp này sẽ tạo ra một định nghĩa lược đồ hoàn toàn mới.

0

Bạn có thể kéo dài tuổi gốc Schema # obj:

const AdminSchema = new mongoose.Schema ({}, Object.assign (UserSchema.obj, {...}))

Ví dụ:

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 

Hoặc sử dụng mô-đun NPM này với phương pháp tương tự:

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

Kiểm tra github repo https://github.com/doasync/mongoose-extend-schema

0

Tất cả những câu trả lời có vẻ khá vô ích phức tạp, với các chức năng helper mở rộng hoặc mở rộng các phương pháp áp dụng cho các giản đồ hoặc sử dụng plugins/discriminators. Tôi đã sử dụng giải pháp sau thay vào đó là đơn giản, sạch sẽ và dễ dàng để làm việc với. Nó định nghĩa một kế hoạch chi tiết cho các lược đồ cơ sở, và sau đó là của schema thực tế được xây dựng bằng cách sử dụng kế hoạch chi tiết:

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; 

quán 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; 

Bạn có thể sử dụng kế hoạch chi tiết cho lược đồ ban đầu như cũ và sử dụng Object.assign bạn có thể mở rộng kế hoạch chi tiết theo bất kỳ cách nào bạn thích cho các giản đồ khác, mà không sửa đổi cùng một đối tượng.