猫鼬保存多层嵌套对象 [英] mongoose save multi level nested objects

查看:72
本文介绍了猫鼬保存多层嵌套对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试实现我的第一个基于猫鼬的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.

还有一些建议:

  1. 最好不要将_id字段添加到架构中,mongodb会 处理.
  2. 如果使用给定的_id进行调查,我认为您会使用它.更好地 使用name字段检查调查是否已存在.
  3. minmax选项用于数字类型,用于字符串类型 使用minlengthmaxlength. 文档
  1. It is better to not add _id fields to the schemas, mongodb will handle it.
  2. I see you use it if a survey exists with the given _id. Better to use name field to check if a survey already exists.
  3. min and max options are used for Number type, for String type minlength and maxlength 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
                }
            ]
        }
    ]
}

这篇关于猫鼬保存多层嵌套对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆