Enum on array with mongoose - javascript

According to the documentation (https://mongoosejs.com/docs/validation.html#built-in-validators):
Strings have enum, match, maxlength and minlength validators.
(the link does point to an invalid zone of the doc).
Is there a way to declare enum on array with mongoose?

Assuming you mean an array of enums, that would be:
const testSchema = new Schema({
name: String,
enums: [{type: String, enum: ['Coffee', 'Tea']}]
});

Related

MongoDB auto pushes arrays into data schemas

I'm being in a case in which I don't know why or what causes it. I can't find any info on this weird problem. So I'm gonna ask here.
//mongoDB data schema
const dataSchema = mongoose.Schema({
userID: String,
userStocks: Array,
stockMarket: Array,
});
module.exports = mongoose.model('Data', dataSchema);
The problem then arrives when creating a new collection in the database:
var regUser = new Data({
});
console.log(regUser); return;
The console.log(regUser) returns both the stockMarket array and userStock array as empty arrays.
Why is this? And how do I prevent it?
It works fine with Number and String type. But with Array type it seems to auto insert it for some reason.
I've tried with delete regUser.stockMarket but it does nothing despite returning true when run. I've also tried removing them with an aggregate using $unset and $merge but still nothing.
So does anyone have any idea what could be causing this weird case? And how would I fix it?
-----------EDIT-----------
Based on the answer from #HuyPham I found out the problem was that I didn't correctly declare it as in array in the schema constructor. The correct way of doing it was:
const dataSchema = mongoose.Schema({
userID: String,
userstocks: {
type: Array,
default: undefined
},
stockMarket: {
type: Array,
default: undefined
}
});
You have defined Array type in mongoose.Schema in the wrong way. Take a look at Arrays in mongoose docs. In case you receive empty array for userStocks and stockMarket maybe it's take Array instance as default value.
In the correct way you found above, make an adjustment from type: Array to type:[] to prevent unpredictable issues when using JavaScript Array instance to set type.
const dataSchema = mongoose.Schema({
userID: String,
userstocks: {
type: [],
default: undefined
},
stockMarket: {
type: [],
default: undefined
}
});

Capitalization of the model name (Mongoose)?

Why the name of the Model is Capitalized.
As in their documentation, they have capitalized it.
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
Why is Tank capitalized here? Is there any specific reason?
Sorry if this is not a good question. Any help would be appreciated :)
This is merely a coding convention. The Tank model is being viewed as an instantiable class:
var small = new Tank({ size: 'small' });
According to typical coding conventions, class names should be UpperCamelCase with the first letter capitalised, and instance variables should be in lowerCamelCase (as should methods).
Reference Mongoose Documentation
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
The first argument is the singular name of the collection your model
is for. ** Mongoose automatically looks for the plural, lowercased
version of your model name. ** Thus, for the example above, the model
Tank is for the tanks collection in the database.

Big numbers break underscore.js _.contains

While debugging a mongoose callback I found out that either underscore.js or the JavaScript language itself seems to have a problem with big numbers.
In the example below, I store a small number, and a String that contains an ObjectId from mongoose (24 digit number), in order to show the problem as clearly as possible.
var users = ["32", "300000000000000000000002"];
alert(_.contains(users, "32")); // true
alert(_.contains(users, (32).toString())); // true
alert(_.contains(users, "300000000000000000000002")); // true
alert(_.contains(users, (300000000000000000000002).toString())); // false - wait wat ?
My question is, of course, how to make the last call return true ?
I would prefer not to convert the array users to an array of numbers, because (1) the array might be huge in a production context, and (2) I may need to do other operations on the array.
The last returns "3e+23" which is not equals to "300000000000000000000002"
The problem was always that I get an input String which is automatically converted to a number (by a library). So I only had to make the 'foreign key' a smaller number. I eventually created a custom number autogenerate function to circumvent this problem:
var autoIncrement = require('mongoose-auto-increment');
var address = require('./Address');
var connection = mongoose.createConnection(address.mongo());
autoIncrement.initialize(connection);
var UserSchema = new mongoose.Schema({ /* property definitions */});
mongoose.model('User', UserSchema);
UserSchema.plugin(autoIncrement.plugin, {
model: 'User',
startAt: 10000001
});
As a result, I had to change the referencing mechanism:
var GroupSchema = new mongoose.Schema({
users: [{type: Number, ref: 'User'}],
/* other property definitions */
});

update a subfield with mongoose

I have a Node.js mongoose schema that looks like this:
var Schema = mongoose.Schema;
var playersSchema = new Schema({
login: String,
pwd: String,
game: {
lat: Number,
lon: Number,
speed: Number,
money: Number
}
});
I want to update only the game.money field of a given element. How can I do that with findByIdAndUpdate ?
MongoDB supports "dot notation" for specifying fields in sub-documents. The same principle applies to either a plain object or an array of objects:
Model.findByIdAndUpdate(id,{ "$set": { "game.money" },function(err,doc) {
});
The $set operator also only updates the specified field or fields without affecting the rest of the document and overwriting the full content.
Also see other field update operators such as $inc to increment an existing number, either up or down.

mongoose js: should documents be embedded when field is not a list?

Below is my Schema.
var UserModel = new Schema({
id: ObjectId
, email: String
, firstName: String
, lastName: String
, password: String
});
var MessageModel = new Schema({
id: ObjectId
, createdDate: { type: Date, default: Date.now }
, user: String // should this be [UserModel]?
, body: String
});
For my case, every message has a user but only one. Should I Embed UserModel or should I leave the user field as a string. One future use case would be to return a query that has the body of the message, creation date, and user (first name and last name concatenated). Thanks.
Short answer: No, you should not use the UserModel as a subdocument of MessgeModel.
Long answer: First, reconsider your naming. You are actually defining schemas here. Later, you will be associating a model with each of these schemas. So, UserSchema and MessageSchema would be more appropriate here.
But that's not germane. Regarding your question, you're MessageModel schema should not contain embedded documents representing users unless there is a 1-to-1 relationship. However, I expect that each user will be associated with many messages (hopefully). So, you don't want a new copy of the user (each with a new _id) for every message he creates. You only want one canonical document for each user, and a reference to that user in the MessageModel.
Now, using a string reference may be the right choice for you. But if you anticipate running a query on the MessageModel in which you'd like the user attribute to be populated by the actual UserModel document, then you'll want to use a ref.

Categories