我的应用程序中有一个看起来像这样的模型:
const EmployeeSchema = new Schema({
firstName: String,
lastName: String,
address: {
street: String,
zipCode: String,
city: {
type: Schema.Types.ObjectId,
ref: 'City',
autopopulate: { select: 'cityName state' }
}
},
...
// and a bunch of other fields
});
module.exports = mongoose.model('Employee', EmployeeSchema, 'employees');
这是我正在使用的主要模型。但是,如果客户端希望从数据库中绘制所有雇员的完整列表,则服务器应返回一个包含所有雇员的大型数组。为了使数据更小,我有另一个模型,该模型仅显示所需信息的摘要,如下所示:
const EmployeeSnippetSchema = new Schema({
firstName: String,
lastName: String,
residenceCity: String,
residenceState: String
});
module.exports = mongoose.model('EmployeeSnippet', EmployeeSnippetSchema, 'employees');
现在,如果客户想要一个包含数据库中所有雇员的完整列表的数组,我只需进行以下调用:
EmployeeSnippet.find()...
在主模式中,“地址”的“城市”字段只是对数据库中其他集合(“城市”)的引用。如何使用EmployeeSnippet进行调用,该调用将从'city'集合中提取'cityName'和'state'值并将其分别填充在'residenceCity'和'residenceState'中? (考虑到这是在服务器从数据库中提取数百(可能是数千)记录的操作期间。)
答案 0 :(得分:0)
好。我找到了一个可行的解决方案,尽管我不知道对于从数据库中提取大量模型文档的情况而言,它是否是最佳选择。但是,无论如何,都是这样。
我需要在代码段的架构上使用post挂钩进行初始化。换句话说,EmployeeSnippet应该如下所示:
const EmployeeSnippetSchema = new Schema({
firstName: String,
lastName: String,
address: {
city: {
type: Schema.Types.ObjectId,
ref: 'City',
autopopulate: { select: 'cityName state' }
}
},
residenceCity: String,
residenceState: String
});
我只添加了以下钩子:
EmployeeSnippetSchema.post('init', function(doc) {
if (doc.address && doc.address.city) {
doc.residenceCity = doc.address.city.cityName;
doc.residenceState = doc.address.state;
}
delete doc.address;
});
这是可行的,尽管正如我之前所说,当我们收到大量文档时,我不知道这是否是一种优化的解决方案,但这是我能想到的最好的方法。
P.S。我只是意识到我使用了“自动填充”功能,而这并不是猫鼬开箱即用的功能。这实际上是猫鼬团队的插件:http://plugins.mongoosejs.io/plugins/autopopulate
答案 1 :(得分:0)
我实际上找到了另一种方法,我认为它是更优化的,因为它将所有这些工作委托给了实际的数据库引擎。这是使用聚合。有了它,我什至不需要为代码段创建一个全新的模型—我可以从主模型中获取它。这是我的方法:
Employee.aggregate()
.lookup({
from: 'cities',
localField: 'residenceAddress.city',
foreignField: '_id',
as: 'residenceAddress'
})
.addFields({
residenceCity: { $arrayElemAt: ['$residenceAddress', 0] },
residenceState: { $arrayElemAt: ['$residenceAddress', 0] }
})
.project({
firstName: 1,
lastName: 1,
residenceCity: '$residenceCity.cityName',
residenceState: '$residenceState.state',
})
.then((result) => {
// do whatever stuff I need with the snippet resulting from this process
});