编辑:,有可能问题是由于修改引起的。我当前的查询如下:
router.route('/projects/:project_id/techDetails')
.get(function(req, res) {
Project.findById(req.params.project_Id, function(err, project) {
if (err)
return res.send(err);
res.json(project);
console.log('get success (project techDetails)');
});
});这将返回null。尽管它在各个方面都与工作代码行相同,但在路由中添加了‘/techDetails’。
原始问题:
我正在用速递和蒙戈构建一个普通的堆栈应用程序。我不知道如何正确地路由到嵌套的文档。
这是我的项目模式
const ProjectSchema = new Schema({
idnumber: { type: Number, required: true },
customername: String,
projectdetails: String,
jobaddress: String,
techDetails: [{
scope: String,
edgedetail: String,
lamination: String,
stonecolour: String,
slabnumber: String,
slabsupplier: String,
purchaseordernum: String,
splashbacks: String,
apron: String,
hotplate: String,
sink: String,
sinkdetails: String,
tappos: String
}],
sitecontactname: String,
sitecontactnum: String,
specialreq: String,
install_date: String,
created_on: { type: Date, default: Date.now },
created_by: { type: String, default: 'SYSTEM' },
active: { type: Boolean, default: true },
flagged: { type: Boolean, default: false },
});我可以使用GET和POST成功地路由到/projects/:project_id,用GET、PUT和DEL成功地路由到/projects/:project_id。
使用PUT路由和项目的_ID,我可以将新条目推送到项目的techDetails子文档数组。生成的JSON数据如下所示:
{
"_id": "59e577e011a3f512b482ef13",
"idnumber": 52,
"install_date": "10/20/2017",
"specialreq": "some...",
"sitecontactnum": "987654321",
"sitecontactname": "bill",
"jobaddress": "123 st",
"projectdetails": "some stuff",
"customername": "B Builders",
"__v": 16,
"flagged": false,
"active": true,
"created_by": "SYSTEM",
"created_on": "2017-10-17T03:24:16.423Z",
"techDetails": [
{
"scope": "Howitzer",
"edgedetail": "12mm",
"lamination": "No",
"stonecolour": "Urban™",
"slabnumber": "1",
"slabsupplier": "Caesarstone",
"purchaseordernum": "no",
"splashbacks": "No",
"apron": "No",
"hotplate": "N/A",
"sink": "N/A",
"sinkdetails": "no",
"tappos": "no",
"_id": "59e577e011a3f512b482ef14"
},
{
"scope": "kitchen",
"edgedetail": "12mm",
"lamination": "etc",
"_id": "59e7da445d9d7e109c18f38b"
},
{
"scope": "Vanity",
"edgedetail": "12mm",
"lamination": "No",
"stonecolour": "Linen™",
"slabnumber": "1",
"slabsupplier": "Caesarstone",
"purchaseordernum": "1",
"splashbacks": "No",
"apron": "No",
"hotplate": "N/A",
"sink": "N/A",
"sinkdetails": "no",
"tappos": "woo",
"_id": "59e81e3324fb750fb46f8248"
}//, more entries omitted for brevity
]
}正如你所看到的,到目前为止,一切都如期而至。但是,现在我需要编辑和删除这个techDetails数组中的各个条目。我还想直接使用projects/:project_id/techDetails和projects/:project_id/techDetails/:techdetails_id路由到它们。
据我所见,有两种方法可以解决这个问题。要么我可以:
( A)为使用techDetails的mergeParams使用新的路由文件。这是我目前正在尝试的方法,但是我不知道如何完成.find来返回所有的techDetails,因为我只能使用Project模型模式,并且我不确定如何访问子文档。
摘录自我的routes.js
const techDetails = require('./techDetails');
//other routes here
//see techdetails file
router.use('/projects/:project_id/techdetails', techDetails);
//here lies an earlier, failed attempt
/* router.route('/projects/:project_id/techdetails/:techDetails_id')
.get(function(req, res) {
Project.findById(req.params.project_id.techDetails_id, function(err,
project) {
if (err)
return res.send(err);
res.json(project.techDetails);
console.log('get success (techDetails)');
});
})
; */还有我的techdetails.js
const express = require('express');
const Project = require('./models/project');
const router = express.Router({mergeParams: true});
router.get('/', function (req, res, next) {
/* Project.find(function(err, techDetails) {
if (err)
return res.send(err);
res.json(techDetails);
console.log('get success (all items)');
}); */
res.send('itemroutes ' + req.params);
})
router.get('/:techDetails_id', function (req, res, next) {
res.send('itemroutes ' + req.params._id)
})
module.exports = router我可以成功地检查路线是否与邮差一起工作,两者都会收到回复。现在的问题是,我不想使用res.send,而是使用res.json和Project.find (或类似的)来获得techDetails。
然而,还有另一种选择:
B)将techDetails文档放入它自己的模式中,然后在项目中填充一个ID数组。
然而,这似乎更复杂,所以如果可以的话,我宁愿避免这样做。
欢迎您提出任何想法和建议。如果需要更多的代码,请告诉我。
发布于 2017-11-01 03:40:39
所以,我找到的解决方案是A)和B的组合。我使用了一个单独的路由文件并将({mergeParams: true})放在路由器声明中,并且为techDetails嵌套模型创建了一个单独的文件,而没有声明它。但是我不相信这两件事都没有任何意义.但不管怎样。
在我的路由中,我得到的工作代码是:
router.use('/projects/:project_id/techDetails', TechDetails);在techDetails.js:中
const router = express.Router({mergeParams: true});
router.route('/')
.get(function(req, res) {
Project.findById(req.params.project_id,
'techDetails', function(err, project) {
if (err)
return res.send(err);
res.json(project);
console.log('get success (project techDetails)');
});
});有什么不同吗?即,'techDetails',行中的Project.findById参数。根据猫鼬API,它充当select语句。唯一的主要区别是我修正了我的原始代码中的一个错误( project_id是project_Id编写的)。可疑的..。)。如果我使用VS或其他什么来代替notepad++,我可能会注意到这一点,但这是我最喜欢的编码领域。
返回res.json(project.techDetails)并删除'techDetails', select参数可能是可能的,但我可能不会测试这个参数。
编辑:最终将techDetails迁移到一个单独的文件中,这意味着它们不再使用objectId生成,这对于PUT和DEL至关重要。我可能在数组声明中使用了一对简单的大括号,但直到我将它重新迁移回项目模式之后,我才想到这一点.
发布于 2017-10-20 00:56:11
在这种情况下,我会将techDetails放在一个单独的模式中:
const ProjectSchema = new Schema({
idnumber: { type: Number, required: true },
customername: String,
projectdetails: String,
jobaddress: String,
techDetails: [techDetailsSchema],
sitecontactname: String,
sitecontactnum: String,
specialreq: String,
install_date: String,
created_on: { type: Date, default: Date.now },
created_by: { type: String, default: 'SYSTEM' },
active: { type: Boolean, default: true },
flagged: { type: Boolean, default: false },
});不要将techDetails模式注册到mongoose.model,因为它是一个子文档。将它放在一个单独的文件中,并在项目模型文件(const techDetailsSchema = require('./techDetails.model');)中要求它。
我将创建如下控制器函数:
GET (all):
module.exports.techDetailsGetAll = function (req, res) {
const projectId = req.params.projectId;
Project
.findById(projectId)
.select('techDetails')
.exec(function (err, project) {
let response = { };
if (err) {
response = responseDueToError(err);
} else if (!project) {
response = responseDueToNotFound();
} else {
response.status = HttpStatus.OK;
response.message = project.techDetails;
}
res.status(response.status).json(response.message);
});
}获得GET (1):
module.exports.techDetailsGetOne = function (req, res) {
const projectId = req.params.projectId;
const techDetailId = req.params.techDetailId;
Project
.findById(projectId)
.select('techDetails')
.exec(function (err, project) {
let response = { };
if (err) {
response = responseDueToError(err);
} else if (!project) {
response = responseDueToNotFound();
} else {
let techDetails = project.techDetails.id(techDetailId);
if (techDetails === null) {
response = responseDueToNotFound();
} else {
response.status = HttpStatus.OK;
response.message = techDetails;
}
}
res.status(response.status).json(response.message);
});
}用于添加POST的:
module.exports.techDetailsAddOne = function (req, res) {
const projectId = req.params.projectId;
let newTechDetails = getTechDetailsFromBody(req.body);
Project
.findByIdAndUpdate(projectId,
{ '$push': { 'techDetails': newTechDetails } },
{
'new': true,
'runValidators': true
},
function (err, project) {
let response = { };
if (err) {
response = responseDueToError(err);
} else if (!project) {
response = responseDueToNotFound();
} else {
response.status = HttpStatus.CREATED;
response.message = project.techDetails; // for example
}
res.status(response.status).json(response.message);
});
}用于使用PUT进行更新
module.exports.techDetailsUpdateOne = function (req, res) {
const projectId = req.params.projectId;
const techDetailId = req.params.techDetailId;
let theseTechDetails = getTechDetailsFromBody(req.body);
theseTechDetails._id = techDetailId; // can be skipped if body contains id
Project.findOneAndUpdate(
{ '_id': projectId, 'techDetails._id': techDetailId },
{ '$set': { 'techDetails.$': theseTechDetails } },
{
'new': true,
'runValidators': true
},
function (err, project) {
let response = { };
if (err) {
response = responseDueToError(err);
res.status(response.status).json(response.message);
} else if (!project) {
response = responseDueToNotFound();
res.status(response.status).json(response.message);
} else {
project.save(function (err) {
if (err) {
response = responseDueToError(err);
} else {
response.status = HttpStatus.NO_CONTENT;
}
res.status(response.status).json(response.message);
})
}
});
}和删除:
module.exports.techDetailsDeleteOne = function (req, res) {
const projectId = req.params.projectId;
const techDetailId = req.params.techDetailId;
Project
.findById(projectId)
.select('techDetails')
.exec(function (err, project) {
let response = { }
if (err) {
response = responseDueToError(err);
res.status(response.status).json(response.message);
} else if (!project) {
response = responseDueToNotFound();
res.status(response.status).json(response.message);
} else {
let techDetail = project.techDetails.id(techDetailId);
if (techDetail !== null) {
project.techDetails.pull({ '_id': techDetailId });
project.save(function (err) {
if (err) {
response = responseDueToError(err);
} else {
response.status = HttpStatus.NO_CONTENT;
}
res.status(response.status).json(response.message);
})
} else {
response = responseDueToNotFound();
res.status(response.status).json(response.message);
}
}
});
}和最终路由如下:
router
.route('/projects')
.get(ctrlProjects.projectsGetAll)
.post(ctrlProjects.projectsAddOne);
router
.route('/projects/:projectId')
.get(ctrlProjects.projectsGetOne)
.put(ctrlProjects.projectsUpdateOne)
.delete(ctrlProjects.projectsDeleteOne);
router
.route('/projects/:projectId/techDetails')
.get(ctrlTechDetails.techDetailsGetAll)
.post(ctrlTechDetails.techDetailsAddOne);
router
.route('/projects/:projectId/techDetails/:techDetailId')
.get(ctrlTechDetails.techDetailsGetOne)
.put(ctrlTechDetails.techDetailsUpdateOne)
.delete(ctrlTechDetails.techDetailsDeleteOne);当我不断地独立于文档的其他部分更新子文档时,我更喜欢这样做。它不创建单独的集合,因此不需要填充。
编辑:This答案将更详细地说明您是应该使用嵌入还是引用。我的答案是嵌入。
https://stackoverflow.com/questions/46840583
复制相似问题