Enforcing the default value in Mongoose schema - javascript

I have been trying to find a way to enforce the default value of a schema so that the default value is being used upon insert regardless of any input parameter. In other words a property of a schema should always have the default value and if any other parameter is being passed on insert/write that passed parameter would be ignored.
As an example, please see my dummy schema below. The property I want to enforce is MySchema.created, which is supposed to store the timestamp of the moment document gets created.
var mongoose = require("mongoose");
var MySchema = new mongoose.Schema({
sendStatus: {
type: String,
enum: ["notsent", "sent", "failed"],
default: "notsent"
},
created: {
type: Date,
default: Date.now
},
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
}
});
I did not find an answer in Mongoose documentation (http://mongoosejs.com/docs/defaults.html) even though it do mention setDefaultsOnInsert, which sounds somewhat close. Altough I would like to do all the schema validation and enforcements on schema level to avoid development mistakes and copy-paste code. Also I don't see how I could use setDefaultsOnInsert for this timestamp, because I want to keep it also constant and not update it upon document update.
Is this possible to achieve? Having a reliable creation date on a document must be a very common use case, but somehow I fail to find a satisfying answer in the internet. Thanks!

You can simply add Mongoose timestamps to the end of your schema and it will timestamp your new/updated document
var MySchema = new mongoose.Schema({
sendStatus: {
type: String,
enum: ["notsent", "sent", "failed"],
default: "notsent"
},
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
}
},{
timestamps:
{
createdAt: 'created_at',
updatedAt: 'updated_at' //leave this out if of no interest
}
});

Related

Mongoose Proper Syntax to Find by Child ID

Using the model.find method I can find documents that match all properties defined within my schema except when a property has a type of mongoose.Schema.ObjectId. In my case, references to the owner of the document. I've tried all sorts of ways to get documents by the owner _id but nothing is working. Anybody know the proper way to do this ?
--EDIT--
Just in case anybody runs into the same issue, I got it working using the following query.
Query:
const users_cars = await Cars.find( { owner: user_id } );
Schema:
const Schema = new mongoose.Schema({
type: Object,
owner: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: [ true, 'car must belong to an owner' ]
},
name: String
});

Mongoose refpath with external reference and internal

My database contains two different collections I have "groups" and I have "users". Each group has a field "participants" which is an array that contains either users or guests. Guests unlike users are stored in the group (since they're bound to the specific group).
I use the "participant" schema as an abstraction object between users/guests and the group, this way I can give different users different privileges.
Now to my problem. What I want is the "participant" schema to work for both users and guests which it would if guests would have been its own collection. However, in this case guests belong to the group object and I'm therefore not sure how I'm supposed to reference it. I've tried enum: ["user", "guests"] and enum: ["user", "meetings.guests"] but without any result. I only get the following error:
MissingSchemaError: Schema hasn't been registered for model "guests".. This tells me that I obviously haven't understood how to reference/link subdocuments in the same collection.
Note that I don't want guests to be their own collection
Maybe I can somehow move the "guest" object to "participants.user" but then I would somehow have to tell mongo that it's not an ObjectId anymore but an object?
Group.model.ts
export const ParticipantSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
required: true,
refPath: "participants.userModel"
},
userModel: {
type: String,
required: true,
enum: ["user", "guests"] // How am I supposed to connect the guests as reference? The guests don't have their own collection, they are stored inside the group
},
privilege: {
type: Number,
required: true
}
})
export const GroupSchema = new Schema({
title: {
type: String,
required: true
},
description: {
type: String
},
participants: [ParticipantSchema],
guests: [GuestSchema]
}, {
timestamps: true
})
export default database.model("group", GroupSchema)
User.model.ts
export const UserSchema = new Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true,
}
}, {
timestamps: true
})
export default database.model("user", UserSchema)

Cast to ObjectId failed for value error in Mongoose findOne

I've been struggling with a weird exception and still confused about it after an hour.
CastError: Cast to ObjectId failed for value "pedrammarandi#gmail.com"
at path "_id" for model "Account"
I'm trying to retrieve an Account via email address. Here is my query
export async function getPendingRecipients(user_id, email_address) {
const account = await Account
.find({email: email_address})
.exec();
return true;
}
This is my Schema object
const userGmailSchema = new Schema({
id: {
type: String,
unique: true
},
displayName: String,
image: Object,
accessToken: String,
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
refreshToken: {
type: String,
default: null
},
email: {
type: String,
unique: true
},
emails: [
{
type: Schema.Types.ObjectId,
ref: 'Emails'
}
]
});
I'm not sure, but I guess the problem is you wrote an id field.
In MongoDB, the "primary key" is _id field, which is an ObjectId object (actually it's a 12-byte-value), and in mongoose, id is a virtual getter of _id, easily said, id is an alias of _id.
(A little different is that, _id returns ObjectId, id returns String version of _id.)
By default, mongoose manage _id field automatically, so commonly we should not write anything about id in schema.
If your id is for something like primary key ID in SQL DB, just remove it from mongoose schema. If it's means something else in your app, try to add an option:
const userGmailSchema = new Schema({
// your schemas here
},
{
{ id: false } // disable the virtual getter
})
or rename it.
http://mongoosejs.com/docs/guide.html#id
Hope this helps.

Does order of schema matter in Node.JS?

Im about to make a huge schema for a form that I have just built... that being said does my schema order have to mimic the form order, or can it just have all the inputs in any order I put them in ?
Example below.
can it be like this?
// link to mongoose
var mongoose = require('mongoose');
// define the article schema
var mapSchema = new mongoose.Schema({
created: {
type: Date,
default: Date.now
},
dd1: {
type: String,
default: ''
},
dd2: {
type: String,
default: ''
},
com1: {
type: String,
default: ''
},
com2: {
type: String,
default: ''
}
});
// make it public
module.exports = mongoose.model('Map', mapSchema);
Or does it have to be like this?
// link to mongoose
var mongoose = require('mongoose');
// define the article schema
var mapSchema = new mongoose.Schema({
created: {
type: Date,
default: Date.now
},
dd1: {
type: String,
default: ''
},
com1: {
type: String,
default: ''
},
dd2: {
type: String,
default: ''
},
com2: {
type: String,
default: ''
}
});
// make it public
module.exports = mongoose.model('Map', mapSchema);
does my schema order have to mimic the form order, or can it just have all the inputs in any order I put them in?
mongoose.Schema accepts a JavaScript object as its parameter. So your question boils down to:
Are JavaScript objects aware of the order their keys were defined in?
The answer to that is: No, key order is not maintained in JavaScript objects. The JS spec explicitly states that objects are unordered key/value collections. (compare)
Therefore it follows that mongoose.Schema could not rely on key order even if it tied to, which means you are free to order the keys in any way you like.
We can also tackle the question from the other end:
Is it likely that a front-end change like form field order forces me to rewrite my database backend code?
And the answer to that is: No, that is pretty darn unlikely. We can dismiss that thought without even looking into any kind of spec, because it would not make any kind of sense.

Whats the reason for not being able to nest Schemas without an array

I was just wondering why something like this isn't allowed in mongoose schema definitions:
var NameSchema = new mongoose.Schema({
first: {type: String, trim: true },
last: {type: String, trim: true }
});
var UserSchema = new mongoose.Schema({
name: NameSchema, // this line causes an error
age: {type: Number}
});
It seems like a design decision, I was just wondering if I could get an explanation as to why it isn't supported
Thanks!
You can nest a schema using this method:
name: [{ some: "props" } ]
or
name: [NameSchema]
The problem with giving directly the schema definition (without using "type: ...") is that Mongoose can't make the difference between the option object and the schema object. Mongoose will think that NameSchema is actually an option object (containing options such as the type, trim...).

Categories

Resources