问题描述
我尝试实现我的第一个基于猫鼬的REST API.
I try to implement my first mongoose based REST API.
我现在尝试了好几天,但无法启动并运行.我想用一系列控件保存调查,并为每个控件保存controlProperties数组.
I tried now for days but cannot get this up and running. I would like to save the survey with an array of controls and for each control an array of controlProperties.
在不同的情况下,我可以保存带有控件数组但没有controlProperties的调查,有时甚至没有控件数组.
In different scenarios I got it to save survey with controls array but without controlProperties and sometime with not even controls array.
有人可以帮助我理解我的错误吗?
Can someone please help me understand my error?
非常感谢.
结构如下:
调查 -控制数组 -controlProperty数组
Survey -- Array of control -- Array of controlProperty
我的模式文件是:
survey.js
survey.js
const mongoose = require('mongoose');
const Control = require('./control');
const surveySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
min: 4,
max: 255
},
description: {
type: String,
required: false,
max: 1000
},
closeDate: {
type: Date,
required: false
},
controls: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Control' }]
});
module.exports = mongoose.model('Survey', surveySchema);
control.js
control.js
const mongoose = require('mongoose');
const Survey = require('./survey');
const controlSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
survey: {type: mongoose.Schema.Types.ObjectId, ref: 'Survey'},
controlType: {
type: String,
required: true
},
name: {
type: String,
required: true
},
isInput: {
type: Boolean,
required: true
},
order: {
type: Number,
required: true
},
controlProperties: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ControlProperty' }]
});
module.exports = mongoose.model('Control', controlSchema);
controlProperty.js
controlProperty.js
const mongoose = require('mongoose');
const Control = require('./control');
mongoose.Schema.Types.String.checkRequired(v => v != null);
const controlPropertySchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
control: { type: mongoose.Schema.Types.ObjectId, ref: 'Control' },
propertyName: {
type: String,
required: true
},
propertyValue: {
type: String,
required: true
},
order: {
type: Number,
required: true
}
})
module.exports = mongoose.model('ControlProperty', controlPropertySchema);
我接收帖子数据的node.js代码是这样的:
My node.js code to receive the post data is this one:
/routes/survey.js
/routes/survey.js
router.post("/", (req, res, next) => {
Survey.find({ _id: req.body._id })
.exec()
.then(result => {
if (result.length >= 1) {
return res.status(409).json({
message: "Survey exists"
});
} else {
const survey = new Survey({
_id: new mongoose.Types.ObjectId(),
name: req.body.name,
description: req.body.description,
closeDate: req.body.closeDate,
order: req.body.order
});
let controlData = req.body.controls;
let arControls = [];
if(controlData != null) {
for (var i = 0, clen = controlData.length; i < clen; i++) {
let c = controlData[i];
let control = new Control({
_id: new mongoose.Types.ObjectId(),
controlType: c.controlType,
name: c.name,
isInput: c.isInput,
order: c.order
})
let controlPropertyData = c.controlProperties;
let arControlProperty = [];
if(controlPropertyData != null) {
for (var j = 0, cplen = controlPropertyData.length; j < cplen; j++) {
let cp = controlPropertyData[j];
let controlProperty = new ControlProperty({
_id: new mongoose.Types.ObjectId(),
propertyName: cp.propertyName,
propertyValue: cp.propertyValue,
order: cp.order
})
arControlProperty.push(controlProperty);
}
ControlProperty.insertMany(arControlProperty, forceServerObjectId=true,function (err,data) {
if(err!=null){
return console.log(err);
}
console.log(" " + j + " controlProperties for control " + i + " saved");
control.controlProperties = data;
console.log(data);
});
}
arControls.push(control);
}
Control.insertMany(arControls, forceServerObjectId=true,function (err,data) {
if(err!=null){
return console.log(err);
}
survey.controls = data;
console.log("controls saved");
console.log(data);
});
}
survey
.save()
.then(result => {
console.log("survey saved");
res.status(201).json(survey);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
}
});
});
示例帖子数据:
{
"name": "TestSurvey",
"description": "This is a test survey",
"controls": [
{
"controlType": "Label",
"name": "Label1",
"isInput": false,
"order": 1,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Large",
"order": 1
},
{
"propertyName": "BackgroundColor",
"propertyValue": "Darkgreen",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "Fill",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "TextColor",
"propertyValue": "White",
"order": 6
},
{
"propertyName": "Text",
"propertyValue": "Paris Work-Life Balance",
"order": 7
}
]
},
{
"controlType": "Label",
"name": "Label2",
"isInput": false,
"order": 2,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Medium",
"order": 1
},
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "Text",
"propertyValue": "Dear [[FirstName]], \nwas your workload on the case 12345 - 67(Company) compliant to the BCG Work Life Balance Ground Rules over the past week ?",
"order": 6
}
]
},
{
"controlType": "PWLBControl",
"name": "PWLB1",
"isInput": true,
"order": 3,
"controlProperties": [
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 1
}
]
},
{
"controlType": "Button",
"name": "button1",
"isInput": false,
"order": 4,
"controlProperties": [
{
"propertyName": "Text",
"propertyValue": "Submit",
"order": 1
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 2
},
{
"propertyName": "IsSubmitButton",
"propertyValue": true,
"order": 3
}
]
},
{
"controlType": "Image",
"name": "image1",
"isInput": false,
"order": 5,
"controlProperties": [
{
"propertyName": "Source",
"propertyValue": "",
"order": 1
},
{
"propertyName": "VerticalOptions",
"propertyValue": "End",
"order": 2
}
]
}
]
}
推荐答案
无需为controlProperties和控件保留单独的集合.您可以将controlPropertySchema
嵌入到controlSchema
中,然后将controlSchema
嵌入到surveySchema
中.因此,最后我们将只有一个收藏集可供调查.
There is no need to keep seperate collections for controlProperties and controls.You can embed controlPropertySchema
inside controlSchema
, and embed controlSchema
inside surveySchema
.So at the end we will have only one collection for survey.
这将使您可以在一个插入操作中创建测量.而且,您还可以通过一次读取操作来获取所有调查信息.
This will make possible to create a survey in one insert operation. And also you will be able to get all survey info in one read operation.
还有一些建议:
- 最好不要将_id字段添加到架构中,mongodb会处理.
- 如果使用给定的_id进行调查,我认为您会使用它.更好地使用
name
字段检查调查是否已存在. -
min
和max
选项用于数字类型,用于字符串类型使用minlength
和maxlength
. 文档
- It is better to not add _id fields to the schemas, mongodb willhandle it.
- I see you use it if a survey exists with the given _id. Better touse
name
field to check if a survey already exists. min
andmax
options are used for Number type, for String typeminlength
andmaxlength
are used. Docs
所以surveySchema
必须看起来像这样:
So the surveySchema
must look like this:
const mongoose = require("mongoose");
const controlPropertySchema = new mongoose.Schema({
// _id: mongoose.Schema.Types.ObjectId,
// control: { type: mongoose.Schema.Types.ObjectId, ref: "Control" },
propertyName: {
type: String,
required: true
},
propertyValue: {
type: String,
required: true
},
order: {
type: Number,
required: true
}
});
const controlSchema = new mongoose.Schema({
//_id: mongoose.Schema.Types.ObjectId,
// survey: {type: mongoose.Schema.Types.ObjectId, ref: 'Survey'},
controlType: {
type: String,
required: true
},
name: {
type: String,
required: true
},
isInput: {
type: Boolean,
required: true
},
order: {
type: Number,
required: true
},
controlProperties: [controlPropertySchema]
//controlProperties: [{ type: mongoose.Schema.Types.ObjectId, ref: "ControlProperty" }]
});
const surveySchema = mongoose.Schema({
// _id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
minlength: 4,
maxlength: 255
},
description: {
type: String,
required: false,
maxlength: 1000
},
closeDate: {
type: Date,
required: false
},
controls: [controlSchema]
// controls: [{ type: mongoose.Schema.Types.ObjectId, ref: "Control" }]
});
module.exports = mongoose.model("Survey", surveySchema);
现在,我们可以使用以下发布路线创建调查:(请注意,由于我们的请求正文的结构与SurveySchema相同,因此我们不进行任何转换)
Now we can create a survey with this post route:(Please note that we don't make any conversions, since our request body's structure is the same as surveySchema)
router.post("/surveys", async (req, res) => {
try {
let survey = await Survey.findOne({ name: req.body.name });
if (survey) {
return res.status(400).send("A survey already exists with that name");
}
const result = await Survey.create(req.body);
res.send(result);
} catch (err) {
console.log(err);
if (err.name === "ValidationError") {
return res.status(400).send(err.errors);
}
res.status(500).send("Something went wrong");
}
});
在您的请求正文中,有一个空的propertyValue
,所以我将其更改为"propertyValue": "I was empty"
,还有一个布尔值而不是字符串,所以我将其更改为"propertyValue": "I was true"
In your request body, there was an empty propertyValue
so I changed it to "propertyValue": "I was empty"
,and also a boolean value instead of string, so I changed it to "propertyValue": "I was true"
您可以使用此更正后的请求正文:
You can use this corrected request body:
{
"name": "TestSurvey",
"description": "This is a test survey",
"controls": [
{
"controlType": "Label",
"name": "Label1",
"isInput": false,
"order": 1,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Large",
"order": 1
},
{
"propertyName": "BackgroundColor",
"propertyValue": "Darkgreen",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "Fill",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "TextColor",
"propertyValue": "White",
"order": 6
},
{
"propertyName": "Text",
"propertyValue": "Paris Work-Life Balance",
"order": 7
}
]
},
{
"controlType": "Label",
"name": "Label2",
"isInput": false,
"order": 2,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Medium",
"order": 1
},
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "Text",
"propertyValue": "Dear [[FirstName]], \nwas your workload on the case 12345 - 67(Company) compliant to the BCG Work Life Balance Ground Rules over the past week ?",
"order": 6
}
]
},
{
"controlType": "PWLBControl",
"name": "PWLB1",
"isInput": true,
"order": 3,
"controlProperties": [
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 1
}
]
},
{
"controlType": "Button",
"name": "button1",
"isInput": false,
"order": 4,
"controlProperties": [
{
"propertyName": "Text",
"propertyValue": "Submit",
"order": 1
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 2
},
{
"propertyName": "IsSubmitButton",
"propertyValue": "I was true",
"order": 3
}
]
},
{
"controlType": "Image",
"name": "image1",
"isInput": false,
"order": 5,
"controlProperties": [
{
"propertyName": "Source",
"propertyValue": "I was empty",
"order": 1
},
{
"propertyName": "VerticalOptions",
"propertyValue": "End",
"order": 2
}
]
}
]
}
这篇关于猫鼬保存多层嵌套对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!