Get Variables Root-Model-Values from Virtual within Subdocument with Mongoose - mongodb

Aloha! Is there any way to access the Root Model from a virtual within a subdocument? Here is my Model-System, should make clear what I'm looking for.
The thing is that "ImageSchema" is going to be included in several places within the Root-Model with diferent "paths" to the Root-Model. "parent()" works sometimes, but not alway.
var ImageSchema = new Schema({
name: String
})
ImageSchema.virtual('url').get(function () {
var parent = this.parent(); // Works
var root = this.root(); // Anything like this available?
return '/'+root.category+'/'+this.name;
});
var CombinationSchema = new Schema({
name: String,
description: String,
images: [ImageSchema]
})
var RootSchema = new Schema({
name: String,
category: String,
description: String,
combinations: [CombinationSchema]
})
Thanks for

Ok, found a solution. This is at least checking for two levels:
ImageSchema.virtual('url').get(function () {
var parent = this.parent()
var root = (parent.parent ? parent.parent() : parent)
console.log(this.parent().description +" "+ root.category + " " + this.name);
});

Related

Re-use POST and GET methods in Express

I'm building a CMS where I have to do a lot of POST and GET requests to my MongoDB. The problem I am having now is that, the more I work on my CMS, the more POST and GET requests I have to do and eventually a lot of double code I'm having in my application. My question is, can I somehow re-use the POST and GET methods? I am using Express framework, MongoDB and Angular on the Front-End.
Here is an example how my application looks like:
Express:
router.post('/news_blocks', function(req, res, next){
var randomNumber = Math.floor(1000 + Math.random() * 9000);
var news_image = req.files.myImage;
news_image.mv('/home//projects/website/public/uploads/' + 'image_' + randomNumber + '.jpg' , function(err) {
if(err){
console.log(err);
}else{
var data = new news_blocks(postOptions(req, randomNumber));
saveToDB(data,res);
}
});
});
router.post('/research', function(req, res, next){
var randomNumber = Math.floor(1000 + Math.random() * 9000);
var research_image = req.files.myImage;
research_image.mv('/home/projects/website/public/uploads/' + 'image_' + randomNumber + '.jpg' , function(err) {
if(err){
console.log(err);
}else{
var data = new research_blocks(postOptions(req, randomNumber));
saveToDB(data,res);
}
});
});
postOptions = function(req, randomNumber){
var options = {
title: req.body.title,
date: new Date,
message: req.body.message,
image: 'image_' + randomNumber
};
return options;
};
MongoDB model:
file1:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var research_block = new mongoose.Schema({
title: String,
date: String,
message: String,
image: String
}, {collection: 'research'});
module.exports = mongoose.model("research", research_block);
File 2:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var news_block = new mongoose.Schema({
title: String,
date: String,
message: String,
image: String
}, {collection: 'news'});
module.exports = mongoose.model("news", news_block);
As you can see, there is a lot of the same code in the POST methods. But I am not sure how I make this more DRY
Suggestion 1:
Make a controller file for every table. And, write functions in it to do all kind of operations in it. And, while calling a service send type of operation along with it. On basis of type you can call any function you want.
Suggestion 2:
Try using GraphQL

Why this MongooseDB population method doesn't work?

I wanted to create a database for MTG combos, and doing something very simple like this, using Mongoose and MLab: We have two schemas, Combo and Card, and two instances of a Card model associated with an instance of a Combo model. When I try to populate the combos of the cards with the name of such combo, it doesn't work and it still shows the ID instead of the name.
var mongoose = require('mongoose') ;
mongoose.connect('mongodb://wernerbusch:xxxx!h#ds115340.mlab.com:15340/wernercito');
var Schema = mongoose.Schema;
var comboSchema = new Schema({
name : String,
cards : [{type: Schema.Types.ObjectId, ref:'Card'}],
type : ["infinite mana", "infinite damage", "draw library", "lethal damage", "storm", "graveyard"]
});
var cardSchema = new Schema({
name: String,
colour:["U","R","B","W","G","C"],
combos: [{type:Schema.Types.ObjectId, ref: 'Combo'}]
})
var Combo = mongoose.model("Combo",comboSchema);
var Card = mongoose.model("Card",cardSchema);
var PanderBurst = new Combo({
name:"PanderBurst",
type:'lethal damage'
})
PanderBurst.save(function(err){
if (err) console.log( err)
var SaprolingBurst = new Card({
name: "Saproling Burst",
colour:["G", "R"],
combos : PanderBurst._id
})
var Pandemonium = new Card({
name: "Pandemonium",
colour:["R"],
combos: PanderBurst._id
})
SaprolingBurst.save(function(err){
if (err) console.log( err)
});
Pandemonium.save(function(err){
if (err) console.log( err)
})
});
Card.find().populate('combos', 'name').exec(function(err,cards){
if (err) console.log (err);
})
After this code is executed, nothing changes in the cards documents.
Have you tried:
Card.find().populate({path: "comboes", select: "name"})
.exec((err,cards)=>{
if (err) console.log (err);
console.log(cards);
});
Using an object has always worked for me.
Update:
you also have:
comboes: {type:Schema.Types.ObjectId, ref: 'Combo'}
in your schema
and combos in your populate.
Final Update:
Populate is used when you make a query. Populating a schema during create isn't good practice because it causes duplication, so call populate with each query.

define authorized values for a Schema's field

Is it possible in Mongoose, to define authorized values for a specific field ?
For example my field "style", would only be allowed to be set to "jazz", "blues" or "rock"
var artistSchema = new mongoose.Schema({
style: {
type: String
// only allow values "jazz", "blues", "rock"
}
});
First of all you are talking about mongoose schema types (String).
You have to know that it is possible to add some options when defining a schema type (options).
According to what you want to do, the option enum seems to be a good choice.
Ps: enum is a built-in validator, what is a validator?
Example from the documentation
var states = 'opening open closing closed'.split(' ')
var s = new Schema({ state: { type: String, enum: states }})
Your case
const CONSTANT_GOOD_VALUES = ['jazz', 'blues', 'rock'];
var artistSchema = new mongoose.Schema({
style: {
type: String
enum: CONSTANT_GOOD_VALUES,
},
});
Try this :-
var artistSchema = new mongoose.Schema({
status: {
type: String,
enum : ['jaz,'blues','rock']
},
});

Adding to an array of lists in mongodb?

Silly question here, but I'm having trouble finding an example on the web.
I have set up a model on mongoDB that has arrays of objects, like so:
var ProjectSchema = new Schema({
project_id: { type: String },
item: {
title: { type: String },
owners: [{
first_name : {type: String} ,
middle_name : {type: String},
other_name: {type: String},
last_name: {type: String},
order: {type: Number, 'default': 1}
}]
}
}]
So you can see that item is a list of fields. And then owners is an array of lists of fields. When I create the project, I'm trying to set the owner like this:
var newProject = new Models.Project({
'item.title': title,
'item.owners[0].last_name': name,
'item.owners[0].order': 1
});
This doesn't generate an error, but the item fields don't get saved either (item.title saves fine).
I tried this too, but it gives me an error:
var newProject = new Models.Project({
'item.title': title,
item.owners.push({last_name: name, order: 1})
});
How am I supposed to refer to these sub-docs so I can save them?
Don't use dot notation in the fields of a new document, create it using the actual structure of the doc instead:
var newProject = new Models.Project({
item: {
title: title,
owners: [{
last_name: name,
order: 1
}]
});
it is a simple JSON object. With Javascript, it is quite straight forward. Below code generates the sample object given in the mongoDB doc:
var address1 = new Object();
address1.street = "123 Fake Street";
address1.city = "Faketon";
address1.state = "MA";
address1.zip = "12345";
var address2 = new Object();
address2.street = "1 Some other Street";
address2.city = "Boston";
address2.state = "MA";
address2.zip = "12345";
var data = new Object();
data._id = "joe";
data.name = "Joe Bookreader";
var addressArray = new Array();
addressArray.push(address1);
addressArray.push(address2);
data.addresses = addressArray;
alert(JSON.stringify(data));

mongoose schema multi ref for one property

How to write multi ref for one property of one mongoose schema, like this(but wrong):
var Schema = mongoose.Schema;
var PeopleSchema = new Schema({
peopleType:{
type: Schema.Types.ObjectId,
ref: ['A', 'B'] /*or 'A, B'*/
}
})
You should add string field to your model and store external model name in it, and refPath property - Mongoose Dynamic References
var Schema = mongoose.Schema;
var PeopleSchema = new Schema({
externalModelType:{
type: String
},
peopleType:{
type: Schema.Types.ObjectId,
refPath: 'externalModelType'
}
})
Now Mongoose will populate peopleType with object from corresponding model.
In the current version of Mongoose i still don't see that multi ref possible with syntax like you want. But you can use part of method "Populating across Databases" described here. We just need to move population logic to explicitly variant of population method:
var PeopleSchema = new Schema({
peopleType:{
//Just ObjectId here, without ref
type: mongoose.Schema.Types.ObjectId, required: true,
},
modelNameOfThePeopleType:{
type: mongoose.Schema.Types.String, required: true
}
})
//And after that
var People = mongoose.model('People', PeopleSchema);
People.findById(_id)
.then(function(person) {
return person.populate({ path: 'peopleType',
model: person.modelNameOfThePeopleType });
})
.then(populatedPerson) {
//Here peopleType populated
}
...