我有projects
存储batches
条记录。使用mongoose从我的mongoDB中检索project
时,我想计算属于该特定项目的批次数。
我的项目模型架构目前如此:
const schema = new Schema({
name: {
type: String,
required: true,
unique: true
},
slug: {
type: String,
required: true,
unique: true
}
}, {
timestamps: true
})
我的批量模型架构看起来:
const schema = new Schema({
project:{
type: ObjectId,
ref: 'Project',
required: true
},
file: {
type: String,
required: true
},
orginal_name: {
type: String,
required: true
}
}, {
timestamps: true
})
我有一个函数,它根据batch.project
字段计算属于项目的批次数,然后将其添加到项目的JSON对象(例如project.batchCount
)。但是我遇到了一个问题,即由模型toJSON或toObject函数删除新字段project.batchCount
,因为该字段在模型模式中不存在。
我目前的解决方案是将它作为'虚拟字段'添加到模型模式中,它永远不会保存到mongoDB中:
const schema = new Schema({
name: {
type: String,
required: true,
unique: true
},
slug: {
type: String,
required: true,
unique: true
},
batchCount: {
type: Number
}
}, {
timestamps: true
})
但是我不喜欢这种方式,因为它使我的模型比需要的更大,而且“可读性”稍差。
有更好的方法吗?如果是这样的话?
答案 0 :(得分:1)
我认为你所寻找的是模式上的虚拟。 mongoose上的文档上的虚拟文件在本地可用,但不会保存到数据库中。
我喜欢在架构上使用静态来获取项目计数的想法。我也喜欢在文档而不是模型上调用方法的想法,所以我在实例方法中实现了它。静态也会起作用。这取决于您的偏好。
以下是我提出的建议:
<强> batch.js 强>
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const batchSchema = new Schema({
project: {
type: Schema.Types.ObjectId,
ref: 'Project',
required: true
},
file: {
type: String,
required: true
},
original_name: {
type: String,
required: true
}
}, {
timestamps: true
});
batchSchema.virtual('projectCount')
.get(function () {
return this._projectCount;
})
.set(function (v) {
this._projectCount = v;
});
batchSchema.methods.count = async function () {
let found = await this.model('Batch').count({ project: this.project });
this._projectCount = found;
};
const Batch = mongoose.model('Batch', batchSchema);
module.exports = Batch;
虚拟调用projectCount有一个简单的setter和getter,如果需要,可以覆盖该值,或者在设置后检索它。
每个文档的实例方法称为count(),并使用查询当前文档的项目_id来调用Model.count()方法。
<强> project.js 强>
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const projectSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
slug: {
type: String,
required: true,
unique: true
}
}, {
timestamps: true
});
const Project = mongoose.model('Project', projectSchema);
module.exports = Project;
<强> populate.js 强>
#!/usr/bin/env node
'use strict';
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const conn = mongoose.connection;
const Batch = require('./batch');
const Project = require('./project');
const projects = [];
const batches = [];
for (let i = 0; i < 10; i++) {
const project = new Project({
name: `project${i}`,
slug: `slug${i}`
});
for (let j = 0; j < 10; j++) {
const batch = new Batch({
project: project._id,
file: `file${j}`,
original_name: `name${j}`
});
batches.push(batch);
}
projects.push(project);
}
async function add () {
await conn.dropDatabase();
const savedProjects = await Project.create(projects);
const savedBatches = await Batch.create(batches);
console.log(`Added ${savedProjects.length} projects.`);
console.log(`Added ${savedBatches.length} batches.`);
return conn.close();
}
add();
populate.js就是我为这个例子创建集合和文档的方式,这里没什么特别的。
<强> get.js 强>
#!/usr/bin/env node
'use strict';
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const conn = mongoose.connection;
const Batch = require('./batch');
async function get () {
let f = await Batch.findOne({});
await f.count();
console.log(`the project for this batch has ${f.projectCount} matches`);
return conn.close();
}
get().catch(console.error);
调用实例方法count()后,我们可以访问存储在虚拟projectCount
中的值。
bash输出
49729301: ./populate.js
Added 10 projects.
Added 100 batches.
49729301: ./get.js
the project for this batch has 10 matches
49729301:
mongo shell输出
49729301: mongo --quiet test
> db.batches.findOne()
{
"_id" : ObjectId("5acbbebb4cd320cb4e403e8f"),
"project" : ObjectId("5acbbebb4cd320cb4e403e8e"),
"file" : "file0",
"original_name" : "name0",
"createdAt" : ISODate("2018-04-09T19:27:55.395Z"),
"updatedAt" : ISODate("2018-04-09T19:27:55.395Z"),
"__v" : 0
}
>
如您所见,虚拟属性仅在本地可用,并且不会存储在数据库中。