Require one field, if another doesn't exists - node.js

To post a message to MongoDB i need to send a schema with a required text field. But even media field exists (as optional) - you can send request without text field. How should I do it? Here is a code:
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var Message = new Schema({
text: {type: String, required: true},
media: {type: Object, required: false}
})

You can try this using function validation as mentioned here
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var Message = new Schema({
text: {
type: String,
required: function() {
return !this.media;
}
},
media: {
type: Object,
required: function() {
return !this.text;
}
})

Related

Error when using _id as a property type in a Mongoose Schema

I am learning MongoDB and mongoose at the moment. I have a Archive and a User schema in mongoose:
archive.js
var mongoose = require('mongoose');
var User = require('../users/user');
var notesSchema = new mongoose.Schema({
author: User.userId,
text: String,
files:[String]
});
var archiveSchema = new mongoose.Schema({
name: String,
priority: String,
deadline: Date,
status: String,
assigned_memnbers: [User.userId],
notes: [notesSchema],
});
archiveSchema.virtual('archiveId').get(function() {
return this._id;
});
module.exports = mongoose.model('Archive', archiveSchema);
user.js:
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
username: String,
mail: String,
bio: String,
password: String
});
userSchema.virtual('userId').get(function() {
return this._id;
});
module.exports = mongoose.model('User', userSchema);
When I run my server i get the error
TypeError: Invalid value for schema path `author`, got value "undefined"
The the problem comes from author: User.userId, but I don't know how to make a reference between the two tables.
For reference, here is what my complete db design more or less looks like:
Any input on how to solve this problem or improve the overall design is welcome. Thanks you.
I think what you're talking about is a reference to other collection:
author: { type: Schema.Types.ObjectId, ref: 'User' }
and
assigned_members: [{ type: Schema.Types.ObjectId, ref: 'User' }]
should work fine.
Source: Mongoose population
I faced the same issue.I had imported a module, It was just not exporting from another module. so I have added:
exports.genreSchema = genreSchema;

How can i generate child model in mongoose

I'm trying to model the following.
I have a parent model that is called Brick that has some attributes.
There will be 5+ type of bricks that will all have their own specific attributes wich are needed also.
I want to be able to select all Bricks of a certain custumer id later, whatever the type (TwitterBrick, facebookBrick et cetera) is.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// set up a mongoose model
module.exports = mongoose.model('Brick', new Schema({
type: String,
userid: { type: String, required: true},
animationspeed: { type: Number, min: 1, max: 100 },
socialsite: String, // none, twitter, instagram
socialsearchtags: String,
tagline: { type: String, minlength:3,maxlength: 25 },
}));
An example for a child is TwitterBrick.
for now it is:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports = mongoose.model('TwitterBrick', new Schema({
bgColor1: String,
bgColor2: String,
bannerBgColor1: String,
bannerBgColor2: String,
}));
TwitterBrick should inherit the attributes of Brick , but i don't know how..
Can you help me in the right direction?
Thanks!
Steven
My solution was to set a new "content" field in brickSchema, and split in different files:
brick.schema.js
var mongoose = require('mongoose');
module.exports = {
type: String,
userid: { type: String, required: true},
animationspeed: { type: Number, min: 1, max: 100 },
socialsite: String, // none, twitter, instagram
socialsearchtags: String,
tagline: { type: String, minlength:3,maxlength: 25 },
content: {type:mongoose.Schema.Types.Mixed, required: false, default: null}
}
brick.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BrickSchema = new Schema(require('brick.schema.js'));
module.exports = mongoose.model('defaultBrick', BrickSchema, 'Bricks');
twitterBrick.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var brickSchema = require('brick.schema.js');
brickSchema.content = new Schema({
bgColor1: String,
bgColor2: String,
bannerBgColor1: String,
bannerBgColor2: String,
});
var BrickSchema = new Schema(require('brick.schema.js'));
module.exports = mongoose.model('twitterBrick', BrickSchema, 'Bricks');
Hope it helps !
Just add the Brick model as an attribute (composition).
It will compensate for that.
Or just rely on exisiting mongoose plugins for that https://github.com/briankircho/mongoose-schema-extend
check this one out.
That's because you didn't "require" the previous file, so technically it's out of scope and the TwitterWallBrickSchema doesn't have a clue what's a "BrickSchema".
Either you put the two models in the same file , or require the first file in the second file.

TypeError object is not a function

I'm developing an application in node.js with MongoDB
I have to files:
product.js and displaycost.js
this is product .js:
var mongoose = require('mongoose');
var Category = require('./category');
var productSchema = {
name:{type: String, require: true},
//Pictures mus start with "http://"
pictures:[{type:String, match: /^http:\/\//i}],
price:{
amount:{type: Number, required: true},
//ONly 3 supported currencies for now
currency:{
type: String,
enum:['USD','EUR','GBP'],
required: true
}
},
category: Category.categorySchema
};
var schema = new mongoose.Schema(productSchema);
var currencySymbols ={
'USD': '$',
'EUR':'€',
'GBP':'£'
};
/*
*
*/
schema.virtual('displayPrice').get(function(){
return currencySymbols[this.price.currency] +
'' + this.price.amount;
});
schema.set('toObject', {virtuals:true});
schema.set('toJSON', {virtuals:true});
module.exports = schema;
What I need is create a record with "productSchema"
I tried with this:
var Product = require('./product.js');
var p = new Product({
name: 'test',
price:{
amount : 5,
currency: 'USD'
},
category: {
name: 'test'
}
});
console.log(p.displayPrice); // "$5"
p.price.amount = 20;
console.log(p.displayPrice); //" $20"
//{... "displayPrice: "$20",...}
console.log(JSON.stringify(p));
var obj = p.toObject();
But when I run the displaycost.js throw me an error at the word "new"
and writes "TypeError: object is not a function"
I don't know why is happening that. Thank you.
you missing export mongoose model with model name.
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
Category = require('./category');
var productSchema = new Schema({
name: {type: String, require: true},
pictures: [{type: String, match: /^http:\/\//i}],
price: {
amount: {type: Number, required: true},
currency: {
type: String,
enum: ['USD', 'EUR', 'GBP'],
required: true
}
},
category: Category
});
var currencySymbols = {
'USD': '$',
'EUR': '€',
'GBP': '£'
};
productSchema.virtual('displayPrice').get(function () {
return currencySymbols[this.price.currency] +
'' + this.price.amount;
});
productSchema.set('toObject', {virtuals: true});
productSchema.set('toJSON', {virtuals: true});
module.exports = mongoose.model('Product', productSchema);
"new" can only be called on a function. not an object.
In program.js you are creating a new instance of the mongoose schema.
var schema = new mongoose.Schema(productSchema);
... more code ...
return schema;
In your other js file you require product. At this point in time product.js has returned an object to you. A new mongoose schema. It is an object which you are refering to as Product.
You then try to create a new instance of it by calling new on the product OBJECT. New cannot be called on an object literal. It can only be called on a function.
I don't believe you need to make a new instance of schema within product.js, just return the function that creates the schema. Then call new on it when you require it like you are in your second file.

Mongoose populate across 2 databases

I have a node app that uses 2 databases. One is the the Names and the other for the rest of all the data.
I have this connection setup:
// DATABASE CONNECTION
var APP_DB_URI = config.APP_DB; // mongodb://localhost:27017/app_db
var app_DB = mongoose.createConnection(APP_DB_URI);
var name_DB = app_DB.useDb(config.NAME_DB); // 'name_db'
This connection is working properly.
There's also no problem upon saving data to both app_db and names_db working perfect.
But the problem is this: when I try to query let say the Account model and then populate the referenced Name model, the populate process returns null.
Account schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var field = {
email: {type: String, unique: true},
password: {type: String, select: false},
name: {type: Schema.Types.ObjectId, ref: 'Name'},
}
var options = {
id: false,
versionKey: false
}
var schema = new Schema(field, options);
module.exports = mongoose.model('Account', schema);
Name schema:
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var field = {
firstName: {type: String, required: true},
middleName: {type: String, required: true},
lastName: {type: String, required: true},
suffix: {type: String, required: false,},
}
var options = {
id: false,
versionKey: false
}
var schema = new Schema(field, options);
module.exports = mongoose.model('Name', schema);
The query and population:
var app_db = *app_db instance passed to this controller*
var Account = app_db.model('Account');
Account.findOne({email:req.body.email})
.populate('name')
.exec(function (err, user) {
if(user){
// user.name returns null
}
})
Is there a special way to populate data from db1 the data from db2? Thanks.
Populate Mongo documents across databases feature added since mongoose v3.9.0. Per this across db populate test, you should different db name when model is called. Some sample codes as below. More details please refer to the test codes in the link.
var app_DB = mongoose.createConnection(APP_DB_URI);
var name_DB = app_DB.useDb(config.NAME_DB); // 'name_db'
// ...
module.exports = app_DB.model('Account', schema);
// ...
module.exports = name_DB.model('Name', schema);
Populate
.populate('name', '', Name)

Closing DB in Mongoose

I have the following code to insert record in Mongo by using Mongoose.
var mongoose = require('mongoose');
var config = require ('config');
var db = mongoose.createConnection(config.database.address, config.database.dbName);
var strCollectionName = 'category';
var CategorySchema = new mongoose.Schema({
categoryName : {type: String, required: true , unique: true },
categoryTag : {type: String},
categoryDescription : {type: String},
createDate : {type: Date, default: Date.now}
});
var createCategory = function (objCategory)
{
var Category = db.model(strCollectionName, CategorySchema );
var objSchema = new Category(objCategory);
objSchema.save(function (err)
{
if (err)
console.log ("Error");
else
console.log ("Success !!");
});
}
I managed to make it work. But if i try to issue db.close () command inside save it throws error otherwise it is good. My questions is I should not have to close the connection at all ? Will Mongoose automatically takes care it ? - Im worried if the connection pool goes beyond the limit then the entire DB might crash.
To do this properly:
Define your models and tell Mongoose about them at the same time. You can do this before you create the connection.
You were previously telling Mongoose about your schema right when you wanted to use it - you only need to do this once, when you create the schema itself.
You can then open a connection for Mongoose which will work across your whole application (i.e. to use it subsequently, you just have to require('mongoose')):
var mongoose = require('mongoose');
var config = require ('config');
var CategorySchema = new mongoose.Schema({
categoryName : {type: String, required: true , unique: true },
categoryTag : {type: String},
categoryDescription : {type: String},
createDate : {type: Date, default: Date.now}
});
mongoose.model('Category', CategorySchema);
mongoose.connect(config.database.address, config.database.dbName);
If you want to manually create and manage connections you can, using .createConnection as in your example above, but unless you know what you're doing it's better to just use Mongoose's default connection.
To create a category:
// if you're in a different file to where you created your CategorySchema, var these:
var mongoose = require('mongoose'),
Category = mongoose.model("Category");
var createCategory = function (objCategory) {
var newCategory = new Category(objCategory);
newCategory.save(function (err) {
if (err)
console.log ("Error");
else
console.log ("Success !!");
});
}

Resources