Using reference in Mongoose with ExpressJS - express

Since I've noticed that deep nesting arrays in documents is not good practice, I wanted to use references in Mongoose using ExpressJS. Now I am making a CMS where there are menu items which the user can post. Each menu item can have sub items that the user can also post. But I don't know how to use referencing so I can reference between the main items collection and the sub items collection.
This is my Main_items Mongoose model:
var menuItems = new mongoose.Schema({
title : String,
subitem: {
type: mongoose.Types.ObjectId,
ref: 'sub_items'
}
}, {collection: 'menu_items'});
module.exports = mongoose.model("menu_items", menuItems);
And the sub_items model:
var subItems = new mongoose.Schema({
title: String,
});
module.exports = mongoose.model("sub_items", subItems);
Post of main_menu items
postController.postMainItems = function(req,res,item){
var saveData = {
title : req.body.title
};
var data = new item(saveData);
saveToDB(data,res);
};
I already created a post for the main menu items. That works. But now I want to know how I can post the sub items so they are directly referenced to each main item

Change the Schema as below, So that you need to insert the main menu first with title and then sub menu with title and parent(_id of parent main menu).
Main Menu Schema:
var menuItems = new mongoose.Schema({
title : String
}, {collection: 'menu_items'});
module.exports = mongoose.model("menu_items", menuItems);
Sub Menu Schema:
var subItems = new mongoose.Schema({
title: String,
parent: { type: mongoose.Types.ObjectId, ref: 'menu_items'}
});
module.exports = mongoose.model("sub_items", subItems);

Related

Mongoose reference not placing ObjectId in parent document

My Mongoose model is not placing ObjectId's in the parent document for referencing to the subdocument in another collection. How can I do this?
These are my models:
menu_items.js
var menuItems = new mongoose.Schema({
title : String,
subitem: [{type: mongoose.Schema.Types.ObjectId,ref: 'sub_items'}]
}, {collection: 'menu_items'});
module.exports = mongoose.model("menu_items", menuItems);
sub_items.js
var subItems = new mongoose.Schema({
title: String,
},{collection: 'sub_items'});
module.exports = mongoose.model("sub_items", subItems);
My subitem post function in ExpressJS:
postController.postSubitems = function(req,res,item) {
var id = req.body.id;
var saveData = {
title: req.body.sub_item
};
var data = new item(saveData);
saveToDB(data,res);
};
You also need to update your menuItem as well. For example, say the _id of your new sub_item is 123456. You need to update your menuItem like so:
menuItem.subitem.push(123456);
menuItem.save();
This will add the _id to the subitem array, and thus give the menuItem a reference to the specified sub_item

find subdocument without start from parent

Pretty new to mongoose. Can I findOne off of a subdocument model?
I have a subdoc called deliverables which is a child of projects
What I'd like to do is FIND on my deliverables model so I don't have to find on the project as
{project.child.child.child.deliverables._id: req.id}
Is that possible or do I have to start from the project model each time? Below is a sample setup I'm using along with my example findOne.
'use strict';
//////////////model/////////////////
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var deliverablesSchema = new Schema({
title:{
type:String,
}
})
var ProjectSchema = new Schema({
name: {
type: String,
},
deliverables: [deliverablesSchema],
});
mongoose.model('Deliverable', deliverablesSchema);
mongoose.model('Project', ProjectSchema);
//////////////controller/////////////////
var mongoose = require('mongoose'),
Project = mongoose.model('Project'),
Deliverable = mongoose.model('Deliverable'),
_ = require('lodash');
exports.findDeliverable = function(req, res) {
Deliverable.findOne({'_id': req.params.deliverableId}).exec(function(err, deliverable) {
if(deliverable){
//return
}
});
};
You can find subdocuments within a document only if you have declared their schema http://mongoosejs.com/docs/subdocs.html
Here is an example taken from here:
Project.findOne({
'_id': myid
}).exec(function (err, p) {
if (p) {
//return
var deriv = p.deliverables.filter(function (oneP) {
return oneP._id === 'myderivableid';
}).pop();
}
});
If your subdocuments are just nested objects in an array you may use Lodash to retrieve that data using _ .where or _.find
Kept digging and found this:
https://stackoverflow.com/a/28952991/2453687
You still have to pull the master document first but it's easy to drill down to the particular object you're looking for and make a quick update, then just update the whole master document in one shot.
Dead simple. Works like a charm.

Mongoose relation not working both ways

I can't get a relationship running between my Rides and Comments controller in my app (built using the yeoman angular-fullstack generator).
Comment model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var CommentSchema = new Schema({
name: String,
comment: String,
active: Boolean,
ride: { type: mongoose.Schema.Types.ObjectId, ref: 'Ride' }
});
module.exports = mongoose.model('Comment', CommentSchema);
Ride model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var RideSchema = new Schema({
name: String,
distance: String,
climb: String,
rating: String,
active: Boolean,
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
module.exports = mongoose.model('Ride', RideSchema);
Accessing /api/comments/ gives me a correct result, containing a related Ride:
{"_id":"54ce818f8c2889da58b01e19","name":"NAAM","comment":"COMMENT","ride":"54ce69647a78532057aa98e0","__v":0}]
Accessing /api/rides/ gives me the following result, without the corresponding Comments:
[{"_id":"54ce69647a78532057aa98e0","name":"Ride test ingevuld","distance":"4000","climb":"1200","rating":"1","__v":0,"comments":[]}]
Can anyone tell me what i am doing wrong?
Example from one of my projects:
exports.insertRoom = function(req, res) {
var id = req.body.id;
var r = req.body.room;
var room = new Room({name: r.name});
Floor.update(
{_id : id},
{
$push: { rooms: room}
},
{upsert:true},
function(floor, err)
{
res.sendStatus(200);
}
);
};
As far as I'am concerned it doesn't work like that. Your comments got it's ride, and your ride got it's comments. I think, you should remove
ride: { type: mongoose.Schema.Types.ObjectId, ref: 'Ride' }
and keep comments inside ride collection.
comments: ['Comment']
It is more objective solution as it supposed to be in MONGO DB which was designed for objective(hierarchial) data.

Dojo CompoButton - onClick event of MenuItem issue with its function

I have the following code in dojo creating a ComboButton with several MenuItems of the correlated Menu:
testfunc = function (input) {
//Code that uses input
}
var menu = new Menu({
id: "saveMenu"
});
//array has 10 json objects and each object has an "Id" field
for(var i=0; i<10; i++) {
var temp = array[i]["Id"];
var menuItem1 = new MenuItem({
label: "Option"+i,
onClick: function() { testfunc(temp); }
});
menu.addChild(menuItem1);
}
var comboButton = new ComboButton({
optionsTitle: "Options",
label: "Combo",
dropDown: menu,
---> onClick:function(){ console.log("Clicked ComboButton"); }
}, "combo");
comboButton.startup();
menu.startup();
I need for each MenuItem its onClick function to pass a different variable in the testfunc. Specifically the value of the array[i]["Id"] which is an array that has 10 json objects. With the above code the parameter that is passed in ALL the testfunc functions of ALL the MenuItems is the last one.
Is it possible to pass for each MenuItem the correct array[i]["Id"] value
i.e.
MenuItem0 -> onClick: testfunc(array[0]["Id"])
MenuItem1 -> onClick: testfunc(array[1]["Id"])
MenuItem2 -> onClick: testfunc(array[2]["Id"])
.
.
.
etc
Thanks
I have found a solution to my problem and I think I should share it.
The issue was solved by passing in the testfunc of the onClick event of the menuItem the parameters using the "this" token e.g.
var menuItem1 = new MenuItem({
id: array[i]["Id"],
label: "Option"+i,
onClick: function() { testfunc(this.id, this.label); }
});

Ext JS 4 - how to change content of an item which can't be referenced by an ID

I would really appreciate any help with the following problem:
I need to be able to change content of an item (div or textfield) but the problem is that there are going to be multiple instances of the same window so I cannot use div IDs.
I tried this little example:
var myBtnHandler = function(btn) {
myPanel.items.items[0].html = "Changed by click!";
myPanel.doLayout();
}
var fileBtn = new Ext.Button({
text : 'Change',
handler : myBtnHandler
});
var panel1 = {
html : 'Original content.'
};
var myPanel = new Ext.Window({
title : 'How to change it?',
items : [
panel1,
fileBtn
]
});
myPanel.items.items[0].html = "Changed on load!";
myPanel.show();
Referencing an element by myPanel.items.items[0] works on load but does not work when it's in the button handler - is it a scope-related problem? How to reference an element without its ID?
Thank you very much,
H.
The problem has nothing to do with scope. The first time you set the html property, the component has not yet been rendered, so on initial render it will read the html property off the component. The second time, you're just setting a property on an object, it's not going to react in any way.
Instead, you should use the update() method.
Ext.require('*');
Ext.onReady(function() {
var myBtnHandler = function(btn) {
myPanel.items.first().update("Changed by click!");
}
var fileBtn = new Ext.Button({
text: 'Change',
handler: myBtnHandler
});
var panel1 = {
html: 'Original content.'
};
var myPanel = new Ext.Window({
title: 'How to change it?',
items: [panel1, fileBtn]
});
myPanel.items.items[0].html = "Changed on load!";
myPanel.show();
});
There are several functions that go through elements that belongs to a container. Try using for example down():
btn = panel.down('button');
Where 'button' parameter would mean 'give me element which type is equal to 'button'. Check out Sencha doc for querying various elements too: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.ComponentQuery
Following on from Sha's reply. To put his advice in context with your example.
var myBtnHandler = function(btn) {
btn.up('window').down('panel').update('Changed by click!');
}
var fileBtn = new Ext.Button({
text : 'Change',
handler : myBtnHandler
});
var panel1 = {
html : 'Original content.'
};
var myPanel = new Ext.Window({
title : 'How to change it?',
items : [
panel1,
fileBtn
]
});
myPanel.show();
myPanel.update('Changed on load!');