Is it possible to add fields not described in Mongoose model? - node.js

For example I have schema like this:
let mongoose = require('mongoose');
let carSchema = new mongoose.Schema({
url: String,
unique: {type: String, index: { unique: true }},
number: String,
title: String,
price: String,
});
module.exports = mongoose.model('Car', carSchema);
When I'm creating new instance is it possible to add extra fields without describing them in the model? For example:
data.bpm = {foo: 'bar'}
new CarModel(data).save(function (err) {
if (err) {
dd(err)
}
})

You can use the strict: false option.
Documentation:
The strict option, (enabled by default), ensures that values passed to our model constructor that were not specified in our schema do not get saved to the db.
Your updated schema will look like this:
let carSchema = new mongoose.Schema({
url: String,
unique: {type: String, index: { unique: true }},
number: String,
title: String,
price: String,
}, { strict: false });

You can use type 'Schema.Types.Mixed' for some field in your schema:
let mongoose = require('mongoose');
let carSchema = new mongoose.Schema({
url: String,
...
data: Schema.Types.Mixed
});
And then use .data field as js object.

You can not since mongoose schema will check if that attribute exists or not, but what you can do is, you can add the following attribute to carSchema:
externalData: Object
And you can set that data to be anything you want.

Related

Mongoose Populate Array of ObjectIDs that utilizes refPath returns empty array

issue.js
const mongoose;
const schema = new mongoose.Schema({
docs: {
type: [mongoose.Schema.Types.ObjectId],
refPath: 'coll',
required: true
},
coll: {
type: String,
required: true,
enum: ['Product', 'Service']
}
});
module.exports = mongoose.model('Issue', schema);
partial index.js
try{
let issues = await Issue.find().populate('docs');
console.log(issues);
//every issue in issues, has an empty 'docs' array, when it should consist of products/services that exist
}catch(e){}
Not sure why arrays is making it not work, I tried making the docs field as singular ObjectId, and it worked fine. Only thing I could think of is that because it's an array, the refPath has to be different, but I'm not sure what I could add, as I tried using 'this.coll'.
I see an error in your schema. Not sure if that is the issue, but you can try.
const mongoose;
const schema = new mongoose.Schema({
docs: [{
type: mongoose.Schema.Types.ObjectId, // <-- This line
refPath: 'coll',
required: true
}],
coll: {
type: String,
required: true,
enum: ['Product', 'Service']
}
});

Mongoose require a field based on some enum values of another field

I have a Mongoose schema Employee. In that I want to store a field (phone number) related to office for the employee, only if he/she is eligible for office, which is only for two levels "senior" and "c-level".
The schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var EmployeeSchema = new Schema({
name: String,
designation: String,
level: {
type: String,
enum: ["intern", "junior", "mid-level", "senior", "c-level"],
required: true,
},
phoneNo: { type: String, required: true },
officePhoneNo: { type: String, required: true } // How to require only if the level is senior or c-level?,
});
Appreciate your help.
Thanks
In Mongoose you can pass a function in required that can return true/false depending on some condition.
It's also possible to depend required of a field on other fields, which is level in your case. That is, you can optionally required a field. Here's how:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const levels = ["intern", "junior", "mid-level", "senior", "c-level"];
const levelsEligibleForOffice = ["senior", "c-level"];
var EmployeeSchema = new Schema({
name: String,
designation: String,
level: {type: String, enum: levels, required: true},
phoneNo: {type: String, required: true},
officePhoneNo: {type: String, required: isEligibleForOffice}
});
function isEligibleForOffice(){
if(levelsEligibleForOffice.indexOf(this.level) > -1){ //"this" contains the employee document at the time of required validation
return true;
}
return false;
}

Schema and subdocs in mongoose.js

Learning how to use mongoose, and am trying to design reliably-variable schemas. The app would post to different services (e.g. Twitter, Tumblr) and store them in one collection ("Posts"). There would be some commonalities (e.g. when it was published, or a short summary) but other fields (like post contents, a blog posts's accompanying scripts) would vary.
What's a good way to approach this? Is there a good way to bind together different collections to avoid this in the first place? References/subschemas? Use Schema.Types.Mixed, and reinforce consistency by extending the default methods with safety checks?
// Example pseudo-functioning schemas
const tweetSchema = new mongoose.Schema({
tweetUrl: {type: string, trim: true}
length: Number
});
const blogSchema = new mongoose.Schema({
title: String,
edits: [Date],
slug: { type: String, trim: true},
body: String
});
const postSchema = new mongoose.Schema({
published: Date,
summary: String,
type: String,
contents: blogSchema || tweetSchema
});
Maybe the discriminators could be better option for your case.
Discriminators are a schema inheritance mechanism. They enable you to have multiple models with overlapping schemas on top of the same underlying MongoDB collection.
Sample codes as below
var options = {discriminatorKey: 'contents'};
const postSchema = new mongoose.Schema({
published: Date,
summary: String,
type: String,
}, options);
var Post = mongoose.model('Post', postSchema);
const tweetSchema = new mongoose.Schema({
tweetUrl: {type: string, trim: true}
length: Number
}, options);
var Tweet = Post.discriminator('Tweet', tweetSchema);
const blogSchema = new mongoose.Schema({
title: String,
edits: [Date],
slug: { type: String, trim: true},
body: String
}, options);
var Blog = Post.discriminator('Blog', blogSchema );

MongoDb.js / Mongoose find() translate a String in ObjectId

I have two schemas utilizing Mongoose
Schema 1
var schema = mongoose.Schema({
name: {
type: String,
required: true
}
});
return mongoose.model('User', schema);
Schema 2
var schema = mongoose.Schema({
name: {
type: String,
required: true
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
}
});
return mongoose.model('Page', schema);
My Data in Page Collection
_id
551b0cdf63dc96e9c39de0f8
551b0d1563dc96e9c39de0f9
551b0d2d63dc96e9c39de0fa
551b0d4363dc96e9c39de0fb
551daae0f4cb312c62dcbc1e
name
Cazaquistao
Russia
China
Australia
El Salvador
user
5515c7aaaf6d59fea26d7185
5515c7aaaf6d59fea26d7185
5515c7aaaf6d59fea26d7185
5515c7aaaf6d59fea26d7185
5515c7c9af6d59fea26d7186
when i search in schema 2 by user, I dont find any results.
The mongoose translate the mongoose converts the query erroneously.
Query
var test = Page.find().select("_id").where({"user" : "5515c7aaaf6d59fea26d7185"}).exec()
.then(function (t) {
console.log("hi", t);
});
Query Translated erroneously
db.pages.find({ user: ObjectId("5515c7aaaf6d59fea26d7185") })
no results
Query as it should be
db.pages.find({ user: "5515c7aaaf6d59fea26d7185" })=
4 results
Any suggestions of what to do to work around this?
If user is a string in your page docs, then your schema needs to reflect that or Mongoose will try and cast it to the type in your schema (ObjectId in this case).
So make user a string in the schema:
var schema = mongoose.Schema({
name: {
type: String,
required: true
},
user: {
type: String,
ref: 'User',
required: true
}
});
I solved passing a objectId rather than a String

Mongoose casting array to string when using $set

I have my model:
var QuestionSchema = new Schema({
title: String,
question: String,
answers: [String],
set_id: String
});
And I update like so:
questionModel.update({
_id: id
}, {
$set: {
title: req.body.title,
question: req.body.question,
answers: req.body.answers
}
}, function (err, numAffected) {
});
I've checked req.body.answers and it is an array, however, it seems to get saved in the DB as foo,bar, as in, a string, not an array!
Any ideas?
answers: req.body.answers[0]
Was the eventual workaround, no idea why!? If anyone can shed any light on why it was coming from a form with inputs: name="answers[]" being passed as [[foo, bar]]...
I suspect that because you've used '[String]' instead of 'Array' in your schema definition, then when you go to update the model, the array is cast to a string, rather than being saved as an array. Try the below:
var QuestionSchema = new Schema({
title: String,
question: String,
answers: Array,
set_id: String
});
It also looks like you would only use brackets around a schema type where you are defining meta properties:
var animalSchema = new Schema({
name: String,
type: String,
tags: { type: [String], index: true } // field level
});

Resources