Mongoose Schema with nested optional object with required fields
Asked Answered
S

5

20

I'd like to create a Mongoose Schema that validates the object below with the following restrictions:

  • field2 is optional (0-1 relationship),
  • field2.type is required if field2 exists (notice that the name of the field is "type" as mongoose reserved word for type definitions),
  • field2 and the the base object must be in the same document.

Code example

{
  field1: "data",
  field2: {
    type: "data",
    data: "data"
  }
}

Thanks in advance.

Sibley answered 31/3, 2015 at 10:15 Comment(3)
Mongoose nested validation is buggy at best. I'd recommend writing your own validation if you're using nested stuff. See github.com/Automattic/mongoose/issues/1919Fassett
@ChrisHoughton thank you. I found Mongoose quite buggy and incomplete. I am considering moving to mongodb driver and code the constrains and validations.Peerage
Possible duplicate of Mongoose Schema with nested optional objectDilemma
K
24

You can refer to this answer:

{
  field1: "value1",
  field2: {
    type: {
      "value2"
    },
    required: false
  }
}

So an example would go:

{
  field1: String,
  field2: {
    type: {
      nestedField1: { type: String, required: true },
      nestedField2: String
    },
    required:false
  }
}

If field2 exists, then nestedField1 would be required.

Kantor answered 8/7, 2017 at 16:56 Comment(3)
Maybe it's because I'm on an older version of Mongoose 5.13.14, but this didn't work for me. @uday answer (https://mcmap.net/q/616582/-mongoose-schema-with-nested-optional-object-with-required-fields) worked for me.Lymphadenitis
Sadly I am getting: Invalid schema configuration: false is not a valid type at path required in Mongoose 8.1.1Farther
@GregWozniak added another answer to the question.Kantor
X
14

@Mina Michael answer didn't worked for me but, when i tweaked a little it worked for me. I tried it like this:

{
  field1: String,
  field2:{
    type: new Schema({
      nestedField1: {type:Boolean,required:true},
      nestedField2: String,
    }),
    required: false
  }
}
Xanthochroism answered 20/2, 2020 at 11:1 Comment(0)
B
0

you may mean something like this:

var Field2Schema = new mongoose.Schema({
  type: { type: String, required: true },
  data: String
});

var MainSchema = new mongoose.Schema({
  field1: String,
  field2: Field2Schema
});
Borglum answered 21/1, 2016 at 9:39 Comment(4)
Downvoted. This can be done in the schema of a single collection, which is what OP wants.Substituent
@EnKrypt: pls provide a proper answer.Ukrainian
Oops, while it looks like I wasn't right about this answer being incorrect outright, this is still not an optimally written solution. There's no need to defined nested schemas and piece them together like this. In longer schemas, not only will the daisy chaining be confusing to maintain, but also slower than just defining the schema for each child object in the same place. Occam's razor applies here.Substituent
I've edited the answer to reflect the simpler, better solution, but since I don't have the required reputation, I need the edit to be approved before SO lets me remove my downvote. Thank you for helping me fix my error, I feel quite embarrassed to be honest.Substituent
E
0

how to insert data with this schema to db.. mainly those nested fields...employee.namefirst = req.body.namefirst;

//first = req.body.namefirst;
employee.name.middle = req.body.namemiddle;
employee.name.last = req.body.namelast; 
Ethanol answered 15/4, 2020 at 17:57 Comment(1)
name: { first: { type: String, required: true }, middle: { type: String, required: false }, last: { type: String, required: true }.. this is my schema definition.. how to insertEthanol
K
0

MongoDB installation link. Another MongoDB installation link.

Below a copy of installation commands for Ubuntu 22.04, not tested.

sudo apt-get install gnupg curl
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org

Command to start MongoD (terminal staying open might appear an idea):

sudo mongod --config /etc/mongod.conf
// sudo mongod --config /etc/mongod.conf
// npm install mongoose
// Above command not tested, but from memory.

let mongoose = require("mongoose");

let schema1 = new mongoose.Schema({
    valueA: String,
    valueB: Buffer,
    valueC: Boolean,
    valueD: Date,
    valueE: Number,
    valueF: mongoose.Schema.Types.Mixed,
    valueG: mongoose.Schema.Types.ObjectId,
    valueH: { type: mongoose.Schema.Types.Array, default: undefined },
    valueI: {
        valueJ: String,
        valueK: Number
    },
    valueL: { type: String, required: false, default: "defaultstring1" },
    valueM: { type: Number, required: true, default: 0 },
    valueN: { type: Date, default: Date.now() }
});

let model1 = mongoose.model('schema1', schema1);

mongoose.connect('mongodb://127.0.0.1:27017/2024February28Connection11111111111111');

// https://www.geeksforgeeks.org/mongoose-document-api/

// Code below might not run in sequence. Printing to console should work, wishing. However, the code running order shouldn't go in sequence. For example, code printing might not go in sequence, and multiple runs in terminal might output non-equal results, or different results.

(async () => await model1.insertMany(
    [
        {valueM: 0},
        {valueM: 1},
        {valueM: 2},
        {valueM: 3},
        {valueM: 4},
        {valueM: 5},
        {},
        {},
        {},
        {},
        {}
    ]))().then(value => {
        
        console.log(value);
        
        (async () => await model1.find())().then(value => {
            
            console.log(value);

            (async () => await model1.insertMany(
                [
                    {
                        valueA: "string0",
                        valueC: true,
                        valueE: 1,
                        valueH: [0,1,2,3,4,5],
                        valueI: { valueJ: "string1", valueK: 1111 }
                    },
                    {
                        valueA: "string1111",
                        valueC: false,
                        valueE: 11111,
                        valueH: ["arrayvalue0", "arrayvalue1", "arrayvalue2", "arrayvalue3", "arrayvalue4", "arrayvalue5"],
                        valueI: { valueJ: "string1111111", valueK: 1111111 }
                    }
                ]))().then(value => {
                    
                    console.log(value);

                (async () => await model1.find())().then(value => {
                    
                    console.log(value)
                    
                    let model1variable1 = new model1(
                        {
                            valueA: "model1variable1valueA0",
                            valueC: false,
                            valueE: 0,
                            valueH: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                            valueI: { valueJ: "model1variable1ValueJ0", valueK: 1 }
                        }
                    );

                    (async () => await model1variable1.save())().then(value => {
                        
                        console.log(value);
                        
                        (async () => await model1.find())().then(value => {
                            
                            console.log(value);
                            
                            (async () => await new model1({}).save())().then(value => {
                                
                                console.log(value);
                                
                                (async () => await model1.find())().then(value => {
                                    
                                    console.log(value);
                                    
                                    (async () => await model1.find({valueM: 5}))().then(value => {
                                        
                                        console.log(value);
                                        
                                        (async () => await model1.find({valueA: "string0"}))().then(value => {
                                            
                                            console.log(value);
                                            
                                            mongoose.connection.close().then(function() {
                                                console.log('Mongoose default(?) connection closed');
                                            });
                                            
                                        }, value => console.log(value));
                                        
                                    }, value => console.log(value));
                                    
                                }, value => console.log(value));
                                
                            }, value => console.log(value));
                            
                        }, value => console.log(value));
                        
                    }, value => console.log(value));
                    
                }, value => console.log(value));
                
            }, value => console.log(value));
            
        }, value => console.log(value));
        
    }, value => console.log(value));

...by the way, in case want to store data not included in data types above, or data types presented by MongoDB or Mongoose or so on, one idea might go transforming it to a string and storing it as a string.

For example, might transform images to strings and store them as strings.

Strings and numbers might achieve many goals in many cases. Strings might work with text and other data types transformed to strings and transformed back, and numbers might work with mathematics and mathematical work, similar to addition and subtraction and multiplication and division and exponentiation and modulo and so on and so forth... . : )

Also, not sure to have found a way around the promise indentation issue, which, to me, appears similar to callback indentation issues, which promises were about solving, thinking.

Kantor answered 29/2 at 10:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.