I'm trying to extract only sub document from an array has the following schema :
const UserSchema = Schema({
name: {
type: String
},library:[{
story:{type: Schema.Types.ObjectId,ref: 'Story'}
}],
});
i tried to use :
module.exports.getUserStories = function(userId, callback){
User.findOne({_id: userId },callback)
.select('library.story')
};
and it gives this result :
{
"_id": "5949615072e15d2b34fa8f9d",
"library": [
{
"story": "592ae46cf2a0ba2b208cb092"
},
{
"story": "592ae608df26d80790092fe9"
},
{
"story": "592ae46cf2a0ba2b208cb092"
}
]
}
but what i'm expecting to get is only this :
[
{
"story": "592ae46cf2a0ba2b208cb092"
},
{
"story": "592ae608df26d80790092fe9"
},
{
"story": "592ae46cf2a0ba2b208cb092"
}
]
I already tried to use double selection like :
module.exports.getUserStories = function(userId, callback){
User.findOne({_id: userId },callback)
.select('library.story')
.select('story')
};
But is gives the same result
Try this one :
module.exports.getUserStories = function(userId, callback){
User.find({_id: userId },{'library.story'}).then(function(user){
if(user){
callback(user.library);
}});
};
Docs here
This output is expected to return by "select" but simply you can prepare the returned data to be as you need as following:
User.findOne({_id: userId }).select('library').then(function(result){
if(result){
//If there is returned item
var stories = result.library;
//Continue ...
}
},function(error){
//Error handling
})
So what I'm asking is how I would show my MongoDB data as JSON on a seprate page? So far I have a database called 'movies' which has a table that contains a bunch of movie titles, rating and stock.
As seen here:
{ "_id" : ObjectId("55e579d30bb58af007d4d8f3"), "movieTitle" : "Iron Man", "rating" : "Excellent", "stock" : "Yes", "sort" : "iron man", "__v" : 0 }
{ "_id" : ObjectId("55e59c3d1d19a3d20ae67a9c"), "movieTitle" : "A Bittersweet Life", "rating" : "Poor", "stock" : "Yes", "sort" : "a bittersweet life", "__v" : 0 }
{ "_id" : ObjectId("55e59c441d19a3d20ae67a9d"), "movieTitle" : "A Team", "rating" : "Okay", "stock" : "No", "sort" : "a team", "__v" : 0 }
I also have the page I want the json to be displayed on:
var express = require('express');
var mongoose = require('mongoose');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('data', {});
});
module.exports = router;
Schema:
var movieSchema = new Schema({
movieTitle: {
type: String,
required: true
},
rating: {
type: String
},
stock: {
type: String,
required: true
},
sort: {
type: String
}
});
Can someone help me out?
I think you could do something like this:
var express = require('express');
var mongoose = require('mongoose');
var router = express.Router();
var movieSchema = new Schema({
movieTitle: {
type: String,
required: true
},
rating: {
type: String
},
stock: {
type: String,
required: true
},
sort: {
type: String
}
});
var Movie = mongoose.model('Movie', movieSchema, 'movies');
mongoose.connect('localhost', function(err, res){
})
/* GET home page. */
router.get('/', function(req, res, next) {
Movie.find({}, function(err, movies) {
res.render('data', movies);
})
});
module.exports = router;
For those who want to see how I got it working:
/* GET home page. */
router.get('/', function(req, res, next) {
// Get Movie schema for use
var Movie = mongoose.model('movie');
// Query all records using aggregate
Movie
.aggregate()
.match({})
.sort({ sort: 1 })
.exec(function(err, movies) {
// Handle errors
if (err) {
return res
.status(500)
.json({
error: err
});
}
// Manipulate movies to tidy up keys
movies.forEach(function (movie) {
movie.id = movie._id;
delete movie._id;
delete movie.__v;
delete movie.sort;
});
return res.json(movies);
});
});
I have a sap.m splitApp where i have an overview of courses. By displaying a course you get detail information like the list of participants for that course. Currently it is only possible to display the participants of the same (one) course for all courses. How can i display the appropriate participants for each course.
If anyone has an idea that would be great :) Thanks.
This is my "Details.view"
sap.ui.jsview("tem_trainer.Details", {
/** Specifies the Controller belonging to this View.
* In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.
* #memberOf tem_trainer.Details
*/
getControllerName : function() {
return "tem_trainer.Details";
},
onBeforeFirstShow: function(oEvent){
this.getController().onBeforeFirstShow(oEvent);
},
/** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed.
* Since the Controller is given to this method, its event handlers can be attached right away.
* #memberOf tem_trainer.Details
*/
createContent : function(oController) {
function dateDiffInDays(a, b) {
// Discard the time and time-zone information.
var utc1 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
var utc2 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
return Math.floor((utc2 - utc1) / (1000 * 60 * 60 * 24));
}
var oTimestamp = new sap.m.ObjectAttribute({
text: '{start} - {end}, {starttime} - {endtime}',
});
var oRoom = new sap.m.ObjectAttribute({
text: "{room}",
});
var oHeader = new sap.m.ObjectHeader({
title: "{name}",
number: "{start}",
numberUnit: "Start Date",
attributes: [
oTimestamp, oRoom
]
});
var oTable = new sap.m.Table("idRandomDataTable", {
headerToolbar : new sap.m.Toolbar({
content : [ new sap.m.Label({
text : "Participant List"
}), new sap.m.ToolbarSpacer({}), new sap.m.Button("idPersonalizationButton", {
icon : "sap-icon://person-placeholder"
}) ]
}),
columns : [
new sap.m.Column({
width : "2em",
header : new sap.m.Label({
text : "Firstname"
})
}),
new sap.m.Column({
width : "2em",
header : new sap.m.Label({
text : "Lastname"
})
}),
new sap.m.Column({
width : "2em",
header : new sap.m.Label({
text : "Job"
})
}),
new sap.m.Column({
width : "2em",
header : new sap.m.Label({
text : "Company"
})
})
]
});
var oModel1 = new sap.ui.model.json.JSONModel();
var model = sap.ui.getCore().getModel();
var aData = model.getProperty("/courses");
oModel1.setData({
modelData : aData
});
oTable.setModel(oModel1);
oTable.bindItems("/modelData/0/participant", new sap.m.ColumnListItem({
cells : [ new sap.m.Text({
text : "{firstname}"
}), new sap.m.Text({
text : "{lastname}"
}), new sap.m.Text({
text : "{job}",
}), new sap.m.Text({
text : "{company}",
}),]
}));
var oIconTabBar = new sap.m.IconTabBar({
items: [
new sap.m.IconTabFilter({
text: "General",
icon: "sap-icon://hint",
content: [
]
}),
new sap.m.IconTabFilter({
text: "Participants",
icon: "sap-icon://visits",
content: [
oTable
]
}),
]
});
return this.page = new sap.m.Page({
title: "Course Details",
content: [
oHeader, oIconTabBar
]
});
}
});
This is my "Details.controller"
sap.ui.controller("tem_trainer.Details", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* #memberOf tem_trainer.Details
*/
// onInit: function() {
//
// },
/**
* Similar to onAfterRendering, but this hook is invoked before the controller's View is re-rendered
* (NOT before the first rendering! onInit() is used for that one!).
* #memberOf tem_trainer.Details
*/
// onBeforeRendering: function() {
//
// },
/**
* Called when the View has been rendered (so its HTML is part of the document). Post-rendering manipulations of the HTML could be done here.
* This hook is the same one that SAPUI5 controls get after being rendered.
* #memberOf tem_trainer.Details
*/
// onAfterRendering: function() {
//
// },
/**
* Called when the Controller is destroyed. Use this one to free resources and finalize activities.
* #memberOf tem_trainer.Details
*/
// onExit: function() {
//
// }
onBeforeFirstShow: function(oEvent){
if(oEvent.data.bindingContext){
// Binding Kontext setzen
this.getView().page.setBindingContext(oEvent.data.bindingContext);
}
},
onListSelect: function(oEvent){
var oBindingContext = oEvent.getParameter(
"listItem").getBindingContext();
var sViewId = "detailCourse_" +
oEvent.getParameter(
"listItem").data("req_id");
sap.ui.getCore().getEventBus().publish(
"nav",
"to", {
viewName: "tem_trainer.Details",
viewId: sViewId,
data: {
bindingContext: oBindingContext
}
});
},
onListItemTap: function(oEvent){
var oBindingContext = oEvent.oSource.getBindingContext();
var sViewId = "detailCourse_" +
oEvent.oSource.data("req_id");
sap.ui.getCore().getEventBus().publish(
"nav",
"to", {
viewName: "tem_trainer.Details",
viewId: sViewId,
data: {
bindingContext: oBindingContext
}
});
},
onNavButtonTap: function(){
// Wird ausgeführt wenn die Hardwaretaste
// oder der Back-Button gedrückt wird
sap.ui.getCore().getEventBus().publish(
"nav", "back");
}
});
This is my "Courses.json"
{
"courses": [
{
"req_id": "1",
"name" : "ABAP OO Basics",
"start" : "20-08-2014",
"end" : "22-08-2014",
"starttime": "10:00:00",
"endtime": "16:00:00",
"status": "Booked",
"room": "Room CDE",
"adress" : "Adress No.1",
"street": "Street No.1",
"zip_code": "74892142578485",
"city": "City No.1",
"country": "Country No.1",
"phone": "0595726764675435497436497",
"fax":"12",
"cap_min": "10",
"cap_opt": "20",
"cap_max": "30",
"img": "./res/1.jpg",
"content": "Test",
"participant": [{ "firstname": "Maik",
"lastname": "Maier",
"job": "installer",
"company": "muster"
},
{ "firstname": "Marco",
"lastname": "Schmidt",
"job": "installer",
"company": "schmitt"
},
{ "firstname": "Hans",
"lastname": "Mueller",
"job": "installer",
"company": "muster"
},
{ "firstname": "Matthias",
"lastname": "Gottlieb",
"job": "installer",
"company": "schmitt"
}]
},
{
"req_id": "2",
"name" : "ABAP OO Basics II",
"start" : "22-08-2014",
"end" : "23-08-2014",
"starttime": "11:00:00",
"endtime": "14:00:00",
"status": "Booked",
"room": "Room XYZ",
"adress" : "Adress No.2",
"street": "Street No.2",
"zip_code": "2222",
"city": "City No.2",
"country": "Country No.2",
"phone": "22222",
"fax":"2222",
"cap_min": "10",
"cap_opt": "20",
"cap_max": "30",
"img": "./res/2.jpg",
"content": "Test",
"participant": [{ "firstname": "Name",
"lastname": "Name",
"job": "installer",
"company": "muster"
},
{ "firstname": "Name2",
"lastname": "Name2",
"job": "installer",
"company": "schmitt"
}]
}
]
}
EDIT: Here is my "Master.controller"
sap.ui.controller("tem_trainer.Master", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* #memberOf tem_trainer.Master
*/
// onInit: function() {
//
// },
/**
* Similar to onAfterRendering, but this hook is invoked before the controller's View is re-rendered
* (NOT before the first rendering! onInit() is used for that one!).
* #memberOf tem_trainer.Master
*/
onBeforeRendering: function() {
var oInbox = sap.ui.getCore().byId("inboxList");
oInbox.removeSelections();
var oJSONDataModel = new sap.ui.model.json.JSONModel();
oJSONDataModel.loadData("./json/Courses.json");
sap.ui.getCore().setModel(oJSONDataModel);
},
/**
* Called when the View has been rendered (so its HTML is part of the document). Post-rendering manipulations of the HTML could be done here.
* This hook is the same one that SAPUI5 controls get after being rendered.
* #memberOf tem_trainer.Master
*/
// onAfterRendering: function() {
//
// },
/**
* Called when the Controller is destroyed. Use this one to free resources and finalize activities.
* #memberOf tem_trainer.Master
*/
// onExit: function() {
//
// }
onBeforeFirstShow: function(oEvent) {
this.bindListData();
if(oEvent.data.title) {
this.getView().page.setTitle(oEvent.data.title);
}
},
bindListData: function(aFilters){
var that = this;
this.getView().oList.bindAggregation("items", {
path: "/courses",
factory: function(sId){
return new sap.m.StandardListItem(sId, {
icon : "sap-icon://course-program",
title: {
path:"name",
},
description: {
path:"start",
},
type: jQuery.device.is.phone?
sap.m.ListType.Navigation : sap.m.ListType.None,
customData: [
new sap.ui.core.CustomData({
key: "req_id",
value: "{req_id}"
}),
],
tap: [that.onListItemTap, that]
}).setInfoState(sap.ui.core.ValueState.Success);
},
filters: aFilters
});
},
onListSelect: function(oEvent){
var oBindingContext =
oEvent.getParameter(
"listItem"
).getBindingContext(),
sViewId = "detailCourse_" +
oEvent.getParameter(
"listItem").data("req_id");
// Ereignis an EventBus übergeben
sap.ui.getCore().getEventBus().publish(
"nav",
"to", {
viewName: "tem_trainer.Details",
viewId: sViewId,
data: {
bindingContext: oBindingContext
}
});
},
onListItemTap: function(oEvent){
// siehe onListSelect
var oBindingContext =
oEvent.oSource.getBindingContext(),
sViewId = "detailCourse_" +
oEvent.oSource.data("req_id");
sap.ui.getCore().getEventBus().publish(
"nav",
"to", {
viewName: "tem_trainer.Details",
viewId: sViewId,
data: {
bindingContext: oBindingContext
}
});
},
//Navigation Zurück
onNavButtonTap: function(){
sap.ui.getCore().getEventBus().publish(
"nav",
"back"
);
},
//Search Functionality
handleSearch: function(oEvent) {
this._updateList();
},
_updateList : function () {
var filters = [];
//var oView = this.getView();
// Filter für die Suche
//var searchString = oView.byId("searchField").getValue();
var searchString = sap.ui.getCore().byId("searchField").getValue();
if (searchString && searchString.length > 0) {
var filter = new sap.ui.model.Filter("name", sap.ui.model.FilterOperator.Contains, searchString);
filters.push(filter);
}
// List Binding updaten
//var list = oView.byId("inboxList");
var list = sap.ui.getCore().byId("inboxList");
var binding = list.getBinding("items");
binding.filter(filters);
},
});
EDIT: This is what i adjusted:
Details.controller
onInit : function() {
var bus = sap.ui.getCore().getEventBus();
bus.subscribe("nav", "to", this.navToHandler, this);
},
navToHandler : function(channelId, eventId, data) {
if (data && data.viewId) {
var oBindingContext = data.data.bindingContext;
this.getView().setBindingContext(oBindingContext);
}
},
//This is a function i already had and which is called by the view
onBeforeFirstShow: function(oEvent){
if(oEvent.data.bindingContext){
// Binding Kontext setzen
this.getView().page.setBindingContext(oEvent.data.bindingContext);
}
},
In my Details.view
var oModel1 = new sap.ui.model.json.JSONModel();
var model = sap.ui.getCore().getModel();
var aData = model.getProperty("/courses");
oModel1.setData({
modelData : aData
});
oTable.setModel(oModel1);
oTable.bindItems("participant", new sap.m.ColumnListItem({
cells : [ new sap.m.Text({
text : "{firstname}"
}), new sap.m.Text({
text : "{lastname}"
}), new sap.m.Text({
text : "{job}",
}), new sap.m.Text({
text : "{company}",
}),]
}));
Your requirement is similar to the demo app of Approve Purchase Orders.
See the json string:
https://openui5.hana.ondemand.com/test/resources/sap/m/demokit/poa/model/mock.json
Courses 1 : n Course 1 : n Participants
PurchaseOrderCollection 1 : n PurchaseOrder 1 :n PurchaseOrder_Items
You already did publish eventbus in your master controller when use selects the list item in the master view:
onListSelect: function(oEvent){
var oBindingContext =
oEvent.getParameter(
"listItem"
).getBindingContext(),
sViewId = "detailCourse_" +
oEvent.getParameter(
"listItem").data("req_id");
// Ereignis an EventBus übergeben
sap.ui.getCore().getEventBus().publish(
"nav",
"to", {
viewName: "tem_trainer.Details",
viewId: sViewId,
data: {
bindingContext: oBindingContext
}
});
},
You need to subscribe the eventbus in your Detail view controller to get the Binding Context of your list item and set the binding context for your detail view, in your case the single course.
onInit : function() {
var bus = sap.ui.getCore().getEventBus();
bus.subscribe("nav", "to", this.navToHandler, this);
},
navToHandler : function(channelId, eventId, data) {
if (data && data.viewId) {
var oBindingContext = data.data.bindingContext;
this.getView().setBindingContext(oBindingContext);
}
},
And adjust your binding paths of the table in the detail view, do not hard code 0.
oTable.bindItems("participant", new sap.m.ColumnListItem({
cells : [ new sap.m.Text({
text : "{firstname}"
}), new sap.m.Text({
text : "{lastname}"
}), new sap.m.Text({
text : "{job}",
}), new sap.m.Text({
text : "{company}",
}),]
}));
I have problems create in my backbone app link with two ids from json. Before I had in template simply variable id. My link was .../tables/ after click to table .../table:id/ But in table is next menu and I need after click to this menu ids from both array, like .../table:id/menu:id there will be showed category view....
My First Tables template
<script type="text/template" id="table-template">
<% _.each(tables, function(table) { %>
<li class="tableli" data-table_id="<%= table.get('id') %>">
<div class="obrazok"></div>
<%= table.get('name') %>
</li>
<% }); %>
</script>
First Tables view
var TablesView = Backbone.View.extend({
initialize:function () {
this.render();
},
tagName: "ul",
events: {
"click li.tableli" : "openMenuItem"
},
openMenuItem: function(e){
currentLink = $(e.currentTarget);
tableId = currentLink.data('table_id');
app.navigate("table" + tableId + "/menus", true);
console.log("table/" + tableId + "/menus");
},
render:function () {
var that = this;
var tables = new Tables();
tables.fetch({
success: function (tables) {
var template = _.template($('#table-template').html(), {tables: tables.models});
that.$el.html(template);
}
})
}
});
Ok After click to one of li I wanna have link like ...table:id/ and open only menus view
My menus view:
<script type="text/template" id="menu-template">
<% _.each(menus, function(menu) { %>
<li class="menucls" data-menu_id="<%= menu.get('id') %>">
<%= menu.get('name') %>
</li>
<% }); %>
</script>
Menu View:
var MenusView = Backbone.View.extend({
initialize:function () {
this.render();
},
tagName: "ul",
events: {
"click li.menucls" : "openMenuItem"
},
openMenuItem: function(e){
currentLink = $(e.currentTarget);
menuId = currentLink.data('menu_id');
tableId = currentLink.parent().data('table_id');
app.navigate("table" + tableId + "/menu" + menuId + "/", true);
console.log("menuId: " + menuId );
console.log("tableId: " + tableId );
},
render:function () {
var that = this;
var menus = new Menus();
menus.fetch({
success: function (menus) {
var template = _.template($('#menu-template').html(), {menus: menus.models});
that.$el.html(template);
}
})
}
});
And there is my goal .... After click I need link like .../table:id/menu:id/
There is my json and collections....
tables.json
[
{"name": "Table 1","stts": "redstts","id": 1},
{"name": "Table 2","stts": "redstts","id": 2},
{"name": "Table 3","stts": "redstts","id": 3},
{"name": "Table 4","stts": "redstts","id": 4},
{"name": "Table 5","stts": "redstts","id": 5}
]
menus.json
[
{"name": "Menu 2","id": 1},
{"name": "Menu 2","id": 2}
]
var Table = Backbone.Model.extend({
defaults: {"name": "Table unahmed"}
});
var Tables = Backbone.Collection.extend({
url: 'api/tables.json',
model: Table
});
var Menu = Backbone.Model.extend({
defaults: {"name": "Menu unahmed"}
});
var Menus = Backbone.Collection.extend({
url: 'api/menus.json',
model: Menu
});
My main js
var AppRouter = Backbone.Router.extend({
routes: {
"" : "tables",
"orders" : "orders",
"tables" : "tables",
"table:id/menus" : "menus",
"products" : "products",
"table:id/menu:id/" : "categories"
},
initialize: function () {
this.headerView = new HeaderView();
$('.header').html(this.headerView.el);
},
tables: function () {
if (!this.TablesView) {
this.TablesView = new TablesView();
}
$('#content').html(this.TablesView.el);
this.headerView.selectMenuItem('tables-menu');
},
menus: function () {
if (!this.MenusView) {
this.MenusView = new MenusView();
}
$('#content').html(this.MenusView.el);
this.headerView.selectMenuItem('menus-menu');
},
categories: function (tableId, menuId) {
if (!this.CategoriesView) {
this.CategoriesView = new CategoriesView();
}
$('#content').html(this.CategoriesView.el);
this.headerView.selectMenuItem('categories-menu');
},
products: function () {
if (!this.ProductsView) {
this.ProductsView = new ProductsView();
}
$('#content').html(this.ProductsView.el);
this.headerView.selectMenuItem('products-menu');
}
});
utils.loadTemplate(['HeaderView'], function() {
app = new AppRouter();
Backbone.history.start();
});
I still try to make function event bud without results... events is function but in link is
#tableundefined/menu1/
I'm very grateful for every answer.
Regards Makromat !!!
You should consider separating out the tables and menus into individual json files because the design you have has the Tables and Menus Backbone collection holding the same data. You should also define a model in each of your collections so the collection knows what object to create.
// tables.json
[
{"id": 1, "name": "Table 1"},
{"id": 2, "name": "Table 2"},
]
// menus.json
[
{"id": 1, "name": "Menu 1"},
{"id": 2, "name": "Menu 2"}
]
var Table = Backbone.Model.extend({
defaults: {"name": "Unnamed Table"}
});
var Tables = Backbone.Collection.extend({
url: 'api/tables.json',
model: Table
});
var Menu = Backbone.Model.extend({
defaults: {"name": "Unnamed Menu"}
});
var Menus = Backbone.Collection.extend({
url: 'api/menus.json'
model: Menu
});
Also, consider taking a look a Backbone's router to handle the change of state as the user clicks on different links.
When you define a route that uses multiple variables, they need to be unique and the function handling the route should define the corresponding parameters.
// sample route
'table:tableId/menu:menuId' : 'categories'
// sample handler
categories: function (tableId, menuId) {
// TODO: use tableId and menuId to set your application's state
// possibly by fetching a specific collection or setting a view's model
}
I am trying to get backbone.js to load json.
The json loads but i am not sure how to get the items into my collection.
Or maybe that happens automatically and i just can't trace out. scope issue?
//js code
//model
var Client = Backbone.Model.extend({
defaults: {
name: 'nike',
img: "http://www.rcolepeterson.com/cole.jpg"
},
});
//collection
var ClientCollection = Backbone.Collection.extend({
defaults: {
model: Client
},
model: Client,
url: 'json/client.json'
});
//view
var theView = Backbone.View.extend({
initialize: function () {
this.collection = new ClientCollection();
this.collection.bind("reset", this.render, this);
this.collection.bind("change", this.render, this);
this.collection.fetch();
},
render: function () {
alert("test" + this.collection.toJSON());
}
});
var myView = new theView();
//json
{
"items": [
{
"name": "WTBS",
"img": "no image"
},
{
"name": "XYC",
"img": "no image"
}
]
}
Your json is not in the correct format, you can fix the json or add a hint to backbone in the parse method:
var ClientCollection = Backbone.Collection.extend({
defaults: {
model: Client
},
model: Client,
url: 'json/client.json',
parse: function(response){
return response.items;
}
});
Or fix your JSON:
[
{
"name": "WTBS",
"img": "no image"
},
{
"name": "XYC",
"img": "no image"
}
]
If you use rest api, try turn off these parameters:
Backbone.emulateHTTP
Backbone.emulateJSON