如何引用尚未注册的Mongoose Schema

时间:2015-11-05 05:08:06

标签: node.js mongodb mongoose mean

此问题类似于:this question

使用Mongoose,我有类似下面的代码。 (我已经使用数字为文件添加了前缀,因此我可以按照它们出现在' models'目录中的顺序加载它们,但仍然可以控制加载顺序。)

在100-employee.server.model.js:

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

var EmployeeSchema = new Schema({
  name: {
    type: String,
    default: ''
  },
  company: {
    type: Schema.ObjectId,
    ref: 'Company'
  },
  subordinates: [EmployeeSchema],
});
mongoose.model('Employee', EmplyeeSchema);

然后,在200-company-server.js中,我有:

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

var CompanySchema = new Schema({
  name: {
    type: String,
    default: ''
  },
  CEO: {
    type: Schema.ObjectId,
    ref: 'Employee'
  }
});
mongoose.model('Company', CompanySchema);

显然,这不起作用,因为公司在注册之前就被引用了。而且,以相反的顺序加载这些并不是出于同样的原因。我需要的是一个逻辑数据结构,如:

{
  name: 'Acme, Inc',
  CEO: {
    name: 'Karen',
    subordinates: [{
      name: 'Bob',
      subordinates: [{
        name: 'Lisa',
        subordinates: []
      },
        name: 'Jerry',
        subordinates: []
      }]
    }]
  }   
}

(我想我的所有括号都已到位。我只是输入了JSON来说明需要。)

我可以将#ObjectId用于'公司'在EmployeeSchema中,但它没有解决问题。我仍然抱怨公司还没有注册。

有人会要求用例,所以这里是:

我有很多公司。我有一个公司员工的等级。而且,我有很多公司。对于每个公司,我需要了解首席执行官,而不必搜索我的所有员工,因为他们没有父母,有一个ObjectId ref公司,但仍然遇到同样的问题。

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

好的,我想出了一个答案,或者至少是一个解决方法。感觉不是很优雅。事实上,我一直不喜欢它,但它确实有效。很想看到更好的解决方案。在100-company-server.js中,首先定义父实体,如下所示:

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

var CompanySchema = new Schema({
  name: {
    type: String,
    default: ''
  },
  CEO: {
    name: {   // This is the company name, so probably a bad example
      type: String,
      default: ''
    }, {
       shoeSize: Number
    }, etc ...
  }
});
mongoose.model('Company', CompanySchema);

这里要注意的关键是,不是让CEO成为ObjectId引用'Employee',而是提供了一个使用与Employee模式相同属性的对象。根据您的使用方式,您可能必须将其强制转换为控制器中的Employee对象。或者,可能有一种聪明的方法来使用虚拟来做同样的事情(http://mongoosejs.com/docs/guide.html)但是,虚拟只需要在EmployeeSchema和模型之后定义。

在200-employee.server.js中,类似于以下内容:

var mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  CompanySchema = mongoose.model('Company').schema;  // so you can use this 
                                                     // after your Employee 
                                                     // is defined

var EmployeeSchema = new Schema({
  name: {
    type: String,
    default: ''
  },
  company: {
    type: Schema.ObjectId,
    ref: 'Company'
  },
  subordinates: [],  // Just an empty array. You fill it with Employees in the controller. You could use a virtual to do the same thing, probably.
});

mongoose.model('Employee', EmployeeSchema);

所以,它有点难看,但它有效。

关键点:

  • 在定义CompanySchema时,不要使用ObjectId ref'Employee'。
  • 而是定义一个看起来像Company对象的对象。
  • 由于此对象没有_id,因此您必须解决此问题 控制器。在我的情况下,这很好。但是,对于许多/大多数用例,这个 可能不会。你必须通过聪明的虚拟解决这个问题 和/或控制器。
  • 使用一个没有类型的简单数组来存储你的孩子(suborinates in 这个例子。 数组运行得很好,并返回对象,就像使用数组一样 ObjectId ref Employee。
  • 让公司引用员工(尚未定义),您 必须将通用对象转换为Employee对象。但是这里有 很多方法都可以做到这一点。
  • 毫无疑问,这是一种更好的方法。