Check for not required property existing in mongoose model variable - javascript

So, I have this mongoose scheemas structure:
const execStatusScheema = new mongoose.Schema(...)
const notifyScheema = new mongoose.Schema({
...
sms: {
type: Boolean,
required: true
},
smsStatus: {
type: execStatusScheema
},
telegram: {
type: Boolean,
required: true
},
telegramStatus: {
type: execStatusScheema
},
voice: {
type: Boolean,
required: true
},
voiceStatus: {
type: execStatusScheema
}
})
const Notify = mongoose.model('Notify', notifyScheema)
module.exports.Notify = Notify
as you can see in Notify scheema smsStatus, voiceStatus and telegramStatus are not required. If sms is false, the smsStatus property is not assiged in my code, and for voice and telegram the same behavior. I want to check in Notify some of these propertys. I do the follow:
const uncomplitedNotifies = await Notify.find(...).select('smsStatus voiceStatus telegramStatus sms voice telegram')
uncomplitedNotifies.forEach(async notify => {
console.log(notify)
if ('telegramStatus' in notify) {
console.log('123')
}
...
Result is:
{ _id: 5ba07aaa1f9dbf732d6cbcdb,
priority: 5,
sms: true,
telegram: false,
voice: false,
smsStatus:
{ status: 'run',
_id: 5ba07aaa1f9dbf732d6cbcdc,
errMessage: 'Authentication failed',
statusDate: '2018-9-18 12:10:19' } }
123
Ok, I find one, and its ok, but my if statment is true even I have no this property in my object. I guess it check in scheema object, where its declared, but I want to check in my 'real' object I got by query.
I also try this checking case, but the same result:
if (typeof something === "undefined") {
alert("something is undefined");
}
How can I check this object correctly ?

The in operator checks the object's own properties and its prototype chain. The unset properties are in the prototype chain of your object, but not on the object's own properties:
const hasTelegramStatus = 'telegramStatus' in document; // true
const hasTelegramStatus = document.hasOwnProperty('telegramStatus') // false
One option is to convert the query into an object by doing document.toObject(), which will remove the prototype chain and only return the own properties.

Related

Mongoose model `this` is undefined in its own definition

I am trying to define a conditional required field for a mongoose model in the following way:
const userSchema = new mongoose.Schema({
email: {
type: String,
},
emailVerified: {
type: Boolean,
required: true
},
hash: {
type: String,
required: function() {
if(!this.emailVerified) return true
return false
}
},
oauth: {
type: Boolean,
required: true,
},
password: {
type: String,
required: function() {
if(this.oauth) return false
return true
}
}
})
export default mongoose.models.Users || mongoose.model('Users', userSchema)
My intention is that I only want the hash field to be required when emailVerified === false, and the password field to be required only when oauth === true.
The thing is that when I try to add a document in the Users collection I get the following error:
Error: Users validation failed: hash: Cannot read property 'emailVerified' of undefined, password: Cannot read property 'oauth' of undefined
By looking at the documentation I understand that I should be able to reference the model in its own definition.

Node.js + Mongoose: How to use a virtual property to associate an ObjectID with the property?

I'm trying to access a MongoDB database using Node.js and Mongoose.
I created a virtual property in Schema called username. See the code that follows.
const mongoose = require("mongoose");
const User = require("../models/user");
const datatypes = ['temperature', 'humidity'];
const nodeSchema = new mongoose.Schema(
{
MACAddress: {
type: String,
required: true,
trim: true,
uppercase: true,
match: /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/,
},
alias: {
type: String,
trim: true,
},
coordinates: {
type: String,
required: false,
match: /^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/,
},
address: {
type: String,
required: false,
},
userID: {
type: mongoose.Types.ObjectId,
},
nodeType: {
type: String,
enum: ['router', 'node'],
default: 'node',
},
dataTypes: {
type: [String],
enum: datatypes,
required: true,
}
},
{
timestamps: true,
}
);
The virtual property is used to set the userID property. See the code that follows.
// virtual field
nodeSchema.virtual("username").set(async function (username) {
this.userID = await this.getUserID(username);
});
// methods
nodeSchema.methods = {
getUserID: function (username) {
if (!username) return null;
return User.find({username: username}).then(userDoc => userDoc[0]._id);
},
};
To add a new document to the database, I am using the following code.
const newNode = new Node(newNodeData);
newNode.save().then( (node) => {
console.log(node.userID)
}
)
The problem is this... Calling the User.find function returns a promise. Even using await (see previous code), newNode.save() saves the document in the database without the userID property.
If I change the code to the following snippet, which doesn't use promise, the userID property is saved in the database with no problem. However, this is not what I want.
// virtual field
nodeSchema.virtual("username").set(async function (username) {
let ObjectId = mongoose.Types.ObjectId;
this.userID = new ObjectId("6245e896afe465a25047302e");
});
How can I force newNode.save() to wait for the promise result before saving the document to the database?

How to pass schema type: Object's key rules

I am trying to understand how to validate, an object using Meteor-Collection2. I can better explain in the code below:
// This is the object structure to validate
// const obj = {
// name: 'Test',
// active: true,
// }
Test.schemaObj = {
someOtherName: {
type: String, // Not the same as obj variable
},
testType: {
type: Object,
// The goal is to define rules for validation for
// things that this will contain.
},
// Inside the object: {
// type: String,
// required: true,
//},
// Inside the object: {
// type: Boolean,
// required: true,
//},
};
I understand that required is automatically set to true when not defined.
My purpose is to basically list all the keys that the object must have and their validation rules. I know how an array of object works, I am just not sure what the syntax is for object validation.
I went through the documentation and stack-overflow, but I was not able to find it anywhere online explicitly showing the syntax.
I am sure that I am missing something basic however, being new to this I was hoping that someone can help me.
I understood which you want to validate the testType object. Then there are two ways:
You can add the blackbox: true, this will allow that object have any structure;
You need to define each property of object, like this:
Test.schemaObj = {
someOtherName: {
type: String, // Not the same as obj variable
},
testType: {
type: Object,
// The goal is to define rules for validation for
// things that this will contain.
},
"testType.attribute1": {
type: String,
required: true,
},
"testType.attribute2": {
type: Boolean,
required: true,
},
};

Mongoose and Nodejs get the name of a user by there ids

I am new to Mongoose and couldn't find an answer elsewhere.
I have a user schema like this:
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
admin: {
type: Boolean,
default: true
},
writer: {
type: Boolean,
default: true
},
producer: {
type: Boolean,
default: true
}
})
And I want to get someone name by their _id
I have this: Users.findById(posts.userID).schema.obj.name but it obviously doesn't return a name, thanks!
findById returns a single document containing the actual values for the properties you've defined in your schema. So if you're just interested in getting the name from the resulting document you can do:
const user = await Users.findById(posts.userID);
const name = user.name;
Any request to mongo via mongoose is asynchronus.
So .findById method return promise-like object.
You need to wait for result via one of three ways:
Pass callback function like
Users.findById(id, function (err, user) {
console.log(user.name);
});
Use .then() like with promise
Users.findById(id).then((user) => {
console.log(user.name);
});
Use async/await:
async function getUser(id) {
const user = await Users.findById(id);
console.log(user.name);
};

When the modifier option is true, validation object must have at least one operator - Collection 2 package - Meteor

I get the following error when trying to create a user :
Exception while invoking method 'createUser' Error: When the modifier option
is true, validation object must have at least one operator
Here is how I am calling the createUser method :
Template.register.events({
"submit #register_form": function(event) {
event.preventDefault();
var $form = $("#register_form");
var attr = {};
var profile = {};
// We gather form values, selecting all named inputs
$("input[name]", $form).each(function(idx) {
var $input = $(this);
var name = $input.attr("name");
if (name == "email" || name == "password") {
attr[ name ] = $input.val();
}
else if (name != "repeat_password") {
profile[ name ] = $input.val();
}
});
attr.profile = profile;
// Creating user account (Cf Accounts module)
Accounts.createUser(attr, function(error) {
console.log(error);
});
},
});
attr has the following value :
And here is how I define the users schema :
// Setting up Simple Schema (cf module)
var profile_schema = new SimpleSchema({
firstname: {
type: String,
regEx: /^[a-z0-9A-Z_]{3,15}$/
},
lastname: {
type: String,
regEx: /^[a-z0-9A-Z_]{3,15}$/
},
celular: {
type: String,
optional: true,
},
});
var schema = new SimpleSchema({
emails: {
type: [Object],
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
profile: {
type: profile_schema,
optional: true,
},
createdAt: {
type: Date
},
});
// Attaching Simple Schema to the users collection (Cf collection2 module)
Meteor.users.attachSchema(schema);
I can't find what is not right. Any suggestion is most welcomed!
Adding my comment as an answer for visibility
You need to add the services object to your user schema as follows
services: {
type: Object,
blackbox: true
}
You need to add this even though you are not using any oAuth because Meteor adds a "service" for email login. You should always have it.

Categories

Resources