Reputation: 407
I want to create a database thats defined by user, each user can have his own flavor of database. So i used strict: false
But Now the problem is I cant make the user define the type
of each schema under the model
const mongoose = require('mongoose');
const testSchema = new mongoose.Schema({
label: {
required: 'please enter label',
trim: true,
type: String
},
url: {
type: String,
trim: true,
},
settings: {} //User defined
}, {
timestamps: true, strict: false
});
module.exports = mongoose.model('test', testSchema);
In the above case, I want the setting to be defined by user like,
{
"label": "About Us",
"url": "www.google.com",
"settings": {
"name": {
"type": "String", //Problem is Here, i can't send datatype directly
"required": true
},
"age": {
"type": "Number",
"required": true,
"enum": [10, 12]
}
}
}
So please tell help me, how can i make the user define the type of the schema?
Upvotes: 2
Views: 6218
Reputation: 1978
Just in case someone is having this issue with NestJS and schemaFactory, that's how I solved it:
...
@Schema({ strict: false })
export class Content {}
@Schema()
export class Deadletter extends Document {
@Prop({type: Header})
header: Header;,
@Prop({type: Metadata})
_metadata?: Metadata;
@Prop({type: Content})
content: any;
}
export const deadLetterFullSchema = SchemaFactory.createForClass(Deadletter);
Upvotes: 1
Reputation: 19372
strict: true
does not mean You can pass anything to settings
field.
It means Your schema format is dynamic - You can have unexpected field names in document that is not defined in schema.
Answer to Your issue:
Seems like You want subdocument, let's make another schema and attach it as type:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const types = Schema.Types;
const testSettingsSchema = new Schema({
name: {
type: types.String,
required: true
},
age: {
type: types.Number,
required: true
enum: [10, 12]
}
},
{
_id : false,
timestamps: false,
strict: false
});
const testSchema = new Schema({
label: {
required: 'please enter label',
trim: true,
type: types.String
},
url: {
type: types.String,
trim: true,
},
settings: {
type: testSettingsSchema,
required: true
}
},
{
timestamps: true,
strict: true
});
module.exports = mongoose.model('test', testSchema);
But to gain more flexibility and avoid creating big test
document (since user may push unpredictable big object), create another schema: testSettings
that points to test_settings
collection and make settings
field to be reference:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const types = Schema.Types;
const testSettingsSchema = new Schema({
name: {
type: types.Mixed
},
age: {
type: types.Mixed
}
},
{
collection: 'test_settings',
timestamps: false,
strict: false // tells to mongoose that schema may "grow"
});
mongoose.model('testSettings', testSettingsSchema);
const testSchema = new Schema({
label: {
required: 'please enter label',
trim: true,
type: types.String
},
url: {
type: types.String,
trim: true,
},
settings: {
type: types.ObjectId,
ref: 'testSettings'
default: null
}
},
{
collection: 'tests',
timestamps: true,
strict: true
});
module.exports = mongoose.model('test', testSchema);
create it as:
const Test = mongoose.model('test');
const TestSettings = mongoose.model('testSettings');
app.post('/tests', async (req, res) => {
try {
const testSettings = await TestSettings.create(req.body.settings);
const test = new Test(req.body);
test.settings = testSettings._id;
await test.save();
res.status(201).send({_id: test._id});
}
catch(error) {
res.status(500).send({message: error.message});
}
});
and on request time get it as:
const Test = mongoose.model('test');
app.get('/tests/:id', async (req, res) => {
try {
const test = await Test.findById(req.params.id)
.populate('settings')
.lean();
res.status(200).send(test);
}
catch(error) {
res.status(500).send({message: error.message});
}
});
Upvotes: 4
Reputation: 13689
define your setting field as Schema.Types.Mixed , so you can able to set any kind of fields inside it , like Number , String , Array , Date , Boolean
..etc
const mongoose = require('mongoose');
const testSchema = new mongoose.Schema({
label: {
required: 'please enter label',
trim: true,
type: String
},
url: {
type: String,
trim: true,
},
settings: {
type:Schema.Types.Mixed ,
default: {}
}
}, {
timestamps: true, strict: false
});
module.exports = mongoose.model('test', testSchema);
While saving the document :
app.post('/save',function(req,res){
var setting = {};
setting.age= req.body.age;
setting.name= req.body.name;
var test = new Test({
test.label: req.body.label;
test.url :req.body.url;
test.setting: setting
});
test.save(function(err){
if(err) {return res.json(err);}
else{ res.json({status:'success',message:'saved.'});}
});
});
Upvotes: 2