gpt4 book ai didi

node.js - 具有不同对象方法的 Mongoose 多类型模式

转载 作者:可可西里 更新时间:2023-11-01 10:03:31 25 4
gpt4 key购买 nike

当我有一个具有多类型属性的集合架构时。比如可以是数字也可以是字符串

我为此使用了 mongoose 的混合类型,但所有验证都消失了。

问题:

var employeeSchema = mongoose.Schema({
_id:false,
title:string,
...
});

EmployeeSchema.methods.(....)//add some methods

var GroupSchema = ({
visitor: {}, // visitor can be an Employee schema or a string of person name
note: string,
time: Date
},{collection:'group'});

如何在 groupSchema 中定义访问者:

  1. 验证检查匹配字符串或保存中的员工。
  2. 从数据库中读取数据时,如果访问者是员工,我可以访问员工方法。

最佳答案

您在这里所追求的实际上是一种“多态性”形式,或者我们通常如何在数据库中将其实现为“鉴别器”。这里的基础知识是一种形式的 Object 继承自另一种形式,但它是自己的对象,具有自己独特的属性以及相关联的方法。

这实际上比仅仅区分普通的“字符串”和更具体的对象更好,而且实现起来相当简单。例如:

var async     = require('async'),
util = require('util'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/company');


function BaseSchema() {

Schema.apply(this,arguments);

this.add({
name: String
});

}

util.inherits(BaseSchema,Schema);

var personSchema = new BaseSchema();

personSchema.methods.speak = function() {
console.log( "my name is %s",this.name );
};

var employeeSchema = new BaseSchema({
title: String
});

employeeSchema.methods.speak = function() {
console.log( "my name is %s, and my title is %s",this.name,this.title );
};

var groupSchema = new Schema({
visitor: { "type": Schema.Types.ObjectId, "ref": "Person" },
note: String,
time: { "type": Date, "default": Date.now }
});

var Person = mongoose.model( 'Person', personSchema ),
Employee = Person.discriminator( 'Employee', employeeSchema ),
Group = mongoose.model( 'Group', groupSchema );


async.waterfall(
[
// Clean data
function(callback) {
async.each([Person,Group],function(model,callback) {
model.remove(callback);
},callback);
},

// Add a person
function(callback) {
var person = new Person({ "name": "Bob" });
person.save(function(err,person) {
callback(err,person);
});
},

// Add an employee
function(person,callback) {
var employee = new Employee({ "name": "Sarah", "title": "Manager" });
employee.save(function(err,employee) {
callback(err,person,employee);
});
},

// Add person to group
function(person,employee,callback) {
var group = new Group({
visitor: person
});
group.save(function(err) {
callback(err,employee);
});
},

// Add employee to group
function(employee,callback) {
var group = new Group({
visitor: employee
});
group.save(function(err) {
callback(err);
});
},

// Get groups populated
function(callback) {
Group.find().populate('visitor').exec(function(err,group) {
console.dir(group);
group.forEach(function(member) {
member.visitor.speak();
});
callback(err);
});
}

],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);

这里是非常基本的输出:

[ { _id: 55d06d984a4690ca1f0d73ed,
visitor: { _id: 55d06d984a4690ca1f0d73eb, name: 'Bob', __v: 0 },
__v: 0,
time: Sun Aug 16 2015 21:01:44 GMT+1000 (AEST) },
{ _id: 55d06d984a4690ca1f0d73ee,
visitor:
{ _id: 55d06d984a4690ca1f0d73ec,
name: 'Sarah',
title: 'Manager',
__v: 0,
__t: 'Employee' },
__v: 0,
time: Sun Aug 16 2015 21:01:44 GMT+1000 (AEST) } ]
my name is Bob
my name is Sarah, and my title is Manager

简而言之,这里有两种“类型”,即“人”和“雇员”。 “人”当然是每个人的基本类型,因此可以有一些基本属性,如果需要的话甚至可以有方法。 “Employee”继承自基础“Person”,因此共享任何属性和方法,并且能够定义自己的属性和方法。

在这里设置 mongoose 模型时,这些是重要的几行:

var Person    = mongoose.model( 'Person', personSchema ),
Employee = Person.discriminator( 'Employee', employeeSchema ),

请注意,“Employee”不使用标准的 mongoose.model 构造函数,而是调用 Person.discriminator。这做了一件特别的事情,实际上“Employee”实际上与“Person”模型共享,但有不同的信息告诉 mongoose 这实际上是一个“Employee”。

还要注意 groupSchema 中“visitor”的构造:

  visitor: { "type": Schema.Types.ObjectId, "ref": "Person" },

如前所述,“Person”和“Employee”实际上与“Person”共享相同的基础模型,但具有一些特定的特征。所以这里的引用告诉 Mongoose 从这个模型中解析存储的 ObjectId 值。

当您调用 .populate() 时,这样做的好处就显而易见了,就像 list 后面所做的那样。当这些引用中的每一个都被解析时,正确的对象类型被替换为那里的值。当 .speak() 方法在“访问者”的每个对象上调用时,这一点变得很明显。

my name is Bob
my name is Sarah, and my title is Manager

您还可以获得其他一些很棒的东西,因为 mongoose 可以做一些事情,例如将“雇员”视为模型并“自动”过滤掉任何查询中不是雇员的任何对象。同样,使用“Person”模型也会显示其中的所有类型(它们由“__t”属性和它的值区分),因此您也可以在各种查询过程中利用它。

嵌入

因此,如果您不喜欢引用,或者通常只是喜欢将所有数据保存在“组”集合中,而不为其他“人”数据单独收集,那么这也是可能的。

这里您真正需要的只是对 list 进行一些更改,特别是在“访问者”作为“混合”类型的模式定义中:

  visitor: Schema.Types.Mixed,

然后不用调用 .populate() 因为所有的数据都已经存在了,你只需要做一些手动的“类型转换”,这实际上很简单:

        group.forEach(function(member) {
member.visitor = (member.visitor.hasOwnProperty("__t"))
? mongoose.model(member.visitor.__t)(member.visitor)
: Person(member.visitor);
member.visitor.speak();
});

然后一切都与嵌入式数据一起“流畅地”工作。

对于使用嵌入式数据的完整列表:

var async     = require('async'),
util = require('util'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/company');

function BaseSchema() {

Schema.apply(this,arguments);

this.add({
name: String
});

}

util.inherits(BaseSchema,Schema);

var personSchema = new BaseSchema();

personSchema.methods.speak = function() {
console.log( "my name is %s",this.name );
};

var employeeSchema = new BaseSchema({
title: String
});

employeeSchema.methods.speak = function() {
console.log( "my name is %s and my title is %s",this.name,this.title );
};

var groupSchema = new Schema({
visitor: Schema.Types.Mixed,
note: String,
time: { "type": Date, "default": Date.now }
});

var Person = mongoose.model( 'Person', personSchema, null ),
Employee = Person.discriminator( 'Employee', employeeSchema, null ),
Group = mongoose.model( 'Group', groupSchema );


async.waterfall(
[
// Clean data
function(callback) {
async.each([Person,Group],function(model,callback) {
model.remove(callback);
},callback);
},

// Add a person
function(callback) {
var person = new Person({ "name": "Bob" });
callback(null,person);
},

// Add an employee
function(person,callback) {
var employee = new Employee({ "name": "Sarah", "title": "Manager" });
callback(null,person,employee);
},

// Add person to group
function(person,employee,callback) {
var group = new Group({
visitor: person
});
group.save(function(err) {
callback(err,employee);
});
},

// Add employee to group
function(employee,callback) {
var group = new Group({
visitor: employee
});
group.save(function(err) {
callback(err);
});
},

// Get groups populated
function(callback) {
Group.find().exec(function(err,group) {
console.dir(group);
group.forEach(function(member) {
member.visitor = (member.visitor.hasOwnProperty("__t"))
? mongoose.model(member.visitor.__t)(member.visitor)
: Person(member.visitor);
member.visitor.speak();
});
callback(err);
});
}

],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);

这与上面的输出相同,创建的对象保留了方便的“鉴别器”信息。所以你可以再次利用之前提到的那么多。

关于node.js - 具有不同对象方法的 Mongoose 多类型模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32033561/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com