I'm trying to create an object in Angular.
Here is my factory
angular.module('myApp')
.factory('Order', function($resource) {
return $resource('/api/products?id=:id/orders?id=:orderId', { id: "#_id" }, {
query: { method: 'GET', isArray: false },
update: { method: 'PUT'}
});
});
Here is my controller
angular.module('myApp').controller('OrderCtrl',
function ($scope, $rootScope, $stateParams, Order, Auth) {
$scope.myOrder = Order.get({"id": 1, "orderId": 1});
}
});
Here is my routes.js file in my server directory
app.use('/api/products', require('./api/product'));
In my api/products directory, I have an index file
var express = require('express');
var controller = require('./product.controller');
var router = express.Router();
// Endpoints for products
router.get('/', controller.index);
router.get('/:id', controller.show);
router.post('/', controller.create);
router.put('/:id', controller.update);
router.patch('/:id', controller.update);
router.delete('/:id', controller.destroy);
// Endpoints for product - order definitions
router.get('/:id/orderDefinitions', controller.showOrderDefinitions);
router.post('/:id/orderDefinitions', controller.addOrderDefinitions);
// Endpoints for product - orders
router.get('/:id/orders', controller.showProductOrders);
router.get('/:id/orders/:orderId', controller.showIndividualProductOrder);
router.put('/:id/orders/:orderId', controller.updateIndividualProductOrder);
router.delete('/:id/orders/:orderId', controller.deleteOrder);
module.exports = router;
Here are the two endpoints I'm trying to access
router.get('/:id/orders/:orderId', controller.showIndividualProductOrder);
router.put('/:id/orders/:orderId', controller.updateIndividualProductOrder);
Here is my controller
exports.showIndividualProductOrder = function(req, res) {
Product.findById(req.params.id, function (err, product) {
if(err) { return handleError(res, err); }
if(!product) { return res.send(404); }
Order.find({productId: product._id, _id: req.params.orderId}, function (err, order) {
console.log("found individual product order", order);
if(err) { return handleError(res, err); }
if(!order) { return res.send(404); }
// Get product's order
return res.json(order[0]);
});
});
};
// Update an individual order for a product
exports.updateIndividualProductOrder = function(req, res) {
Order.find({productId: product._id, _id: req.params.orderId}, function (err, order) {
if(err) { return handleError(res, err); }
if(!order) { return res.send(404); }
var updatedOrder = _.merge(order, req.body);
console.log("updating order", order, updatedOrder);
updatedOrder.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, product);
});
});
};
And yet, I still get this error
Error: [$resource:badcfg] Error in resource configuration for action get. Expected response to contain an object but got an array (Request: GET /api/products?id=1/orders?id=1)
I used Postman to test the API endpoints, and the JSON output is an array. But in my factory, I clearly stated that I didn't want an array with the isArray option.
I used Postman to test the API endpoints, and the JSON output is an array. But in my factory, I clearly stated that I didn't want an array with the isArray option.
With the isArray flag you don't specify what you want, you specify what is to be expected on that particular API endpoint.
If you don't want an array, change the backend code, but if it is an array, then use isArray: true in the configuration.
Edit: you can use the tranformResponse property to specify a converter function for the data, which would enable you to use an endpoint returning an object, but still use a resource method configured for an array with isArray:true (and vice versa), see this answer for an example.
Related
I'm trying to use the mongoDB and update the status of a current document. My backend is receiving the routes my mongoDB update isn't going through.
router.post('/orders_drivers', function (req, res, next) {
console.log(req.body);
Order.update({_id:objectId(req.body.id)}, {$set: {driver:req.body.driver, driverReq:false}}).then (function (order) {
console.log('UPDATE new driver');
}).catch (next)
});
when I log the req.body, the ID I receive and the new $set parameters are correct, but the command never goes through. Any suggestions? I don't receive any errors either which I think is strange.
Mongo version is v4.0.2
I have many other routes that all work correctly.
There is no version issue. you are calling then function on non promiseable value.
You need to call a callback function inside of update.
const mongoose = require('mongoose');
router.post('/orders_drivers', function (req, res, next) {
console.log(req.body);
Order.update({
_id: mongoose.Types.ObjectId(req.body.id)
},
{
$set: {
driver:req.body.driver, driverReq:false
}
},
{ new: true }, // If you want to return updated order
function (err, updatedOrder) {
if (err) throw err;
console.log('UPDATE new driver', updatedOrder);
})
});
You don't need to convert req.body.id into mongoose ObjectId if it already is.
Hey I can't seem to get any results whilst using the req.body. Trying to get out the data from my mongodbdatabase to json format Here is my code:
My server file:
app.get('/api/category/posts', (req, res) => {
Post.find({ categoryId: req.body._id }, function(err, posts) {
res.json(posts);
});
});
Service file:
getPosts(_id): Observable<Post[]>{
return this.http.get<Post[]>(this.apiUrl +"/category/posts");
}
component.ts
this.appService.getPosts(_id)
.subscribe(data =>this.posts=data);
your api method is get method and you want _id in req.body. which is wrong.
you need to either change you get request to post in server file and service file both or try to pass _id in req.params or req.query:-
If you pass _id as req.query :-
your server code will be like:-
app.get('/api/category/posts', (req, res) => {
Post.find({ categoryId: req.query._id }, function(err, posts) {
res.json(posts);
});
});
service file
getPosts(_id): Observable<Post[]>{
return this.http.get<Post[]>(this.apiUrl +"/category/posts"+'?_id='+_id);
}
component.ts will be same.
and if you want to use post method to check for req.body then your code will be changed as following:-
your server code will be like:-
app.post('/api/category/posts', (req, res) => {
Post.find({ categoryId: req.body._id }, function(err, posts) {
res.json(posts);
}); });
service file
getPosts(_id): Observable<Post[]>{
return this.http.post<Post[]>(this.apiUrl +"/category/posts",{_id:_id});
}
component.ts will be same.
Following REST architecture to get resources, you should pass the the _id in the get request parameters. You can also validate your id parameter making sure the passed id is a number using a simple regex pattern
Express route
app.get('/api/category/posts/:id(\\d+)', (req, res) => {
Post.find({ categoryId: req.params.id }, function(err, posts) {
res.json(posts);
});
});
service file
getPosts(_id): Observable<Post[]>{
return this.http.get<Post[]>(`${this.apiUrl}/category/posts/${_id}`);
}
component file
this.appService.getPosts(_id)
.subscribe(data =>this.posts=data);
As a good practice, you should also keep track of your subscriptions and unsubscribe from them when you are done or on component destroy, or use the first operator to unsubscribe after first subscription.
I'm actually creating a chat like Discord with servers and channels using Node.JS, MongoDB and Mongoose.
Actually, my structure is this one:
https://github.com/copostic/My-Simple-Chat/tree/master/models
But to get the conversations, I have to make so much nested functions and I would like to know if there was a better way to organize my code..
Here's the code with the nested functions, I'm trying to get the message list of each channel of each server:
"use strict"
const Server = require('../models/server'),
Channel = require('../models/channel'),
Message = require('../models/message'),
User = require('../models/user');
exports.getChannels = function (req, res, next) {
// Only return one message from each conversation to display as snippet
Server.find({members: req.session._id})
.select('_id')
.exec(function (err, servers) {
if (err) {
res.send({ error: err });
return next(err);
}
servers.forEach(function (server) {
Channel.find({ serverId: server })
.exec(function (err, channels) {
// Set up empty array to hold conversations + most recent message
let fullConversations = [];
channels.forEach(function (channel) {
Message.find({
'channelId': channel._id
})
.sort('creationDate')
.limit(1)
.populate({
path: "author",
select: "profile.firstName profile.lastName"
});
.exec(function (err, message) {
if (err) {
res.send({
error: err
});
return next(err);
}
fullConversations.push(message);
if (fullConversations.length === conversations.length) {
return res.status(200).json({
conversations: fullConversations
});
}
});
});
});
});
});
};
Thanks a lot
I am new to sails.js and when I'm trying to learn it by making a simple web app, I encountered a problem. My app is about class management. My model has 3 table: student, course and list. The student table save information about students, course save information about courses. The list.table save information about which student is in a course and their mark, their absent days in this class. I used res.view() and it worked for any view that need one array. However, when I try to write function which need information from 2 model: student and course, res.view() didnt help (or I dont know to do it properly)
module.exports = {
'new': function(req, res, next) {
Course.find(function foundCourses (err, courses) {
if (err) return next(err);
res.view({courses: courses});
});
/* Student.find(function foundStudents (err, students) {
if (err) return next(err);
res.view({
students: students
});
}); */
},
//more other code here
};
There, I want to send both array to view but I dont know how. Sails.js only let me send one array if I do like that. Please help me . Thank you a lot!
You can't call res.view twice. You need to gather all data first and than send it to view.
2 methods:
module.exports = {
'new': function(req, res, next) {
var foundCourses = function (err, courses) {
if (err) return next(err);
Student.find(function foundStudents (err, students) {
if (err) return next(err);
res.view({
courses: courses,
students: students
});
});
});
Course.find(foundCourses);
},
//more other code here
};
or you can use async.parallel
module.exports = {
'new': function(req, res, next) {
var dataCallback = function (err, data) {
if (err) return next(err);
var courses = data[0];
var students = data[1];
res.view({
courses: courses,
students: students
});
};
async.parallel([
function(callback) {
Course.find(callback);
},
function(callback) {
Student.find(callback);
}
],dataCallback);
},
};
Suppose each users has huge amount of data that no need to store those in single table. I want to store each user's data in separate database for faster query.
I want when any user logging in loopback, change datasets based on users connection strings that stored in User model.
I read all of loopback docs and try so many practice to do this but i can't implement this.
I try this in server/server.js:
app.use(loopback.context());
app.use(loopback.token());
app.use(function (req, res, next) {
if (!req.accessToken) {
return next();
}
app.models.User.findById(req.accessToken.userId, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
return next(new Error('No user with this access token was found.'));
}
console.log('server.js');
var loopbackContext = loopback.getCurrentContext();
if (loopbackContext) {
loopbackContext.set('currentUser', user);
}
var DataSource = require('loopback-datasource-juggler').DataSource;
var ds = new DataSource('memory');
app.datasources.db= ds;// <----- IT DOES'NT WORKING
next();
});
});
but IT DOES'NT WORKING (marked in code).
Any idea to solve this issue?
You can use attachTo() function to attach a datasource based on conditions.
app.use(loopback.context());
app.use(loopback.token());
app.use(function (req, res, next) {
if (!req.accessToken) {
return next();
}
app.models.User.findById(req.accessToken.userId, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
return next(new Error('No user with this access token was found.'));
}
//console.log('server.js');
var loopbackContext = loopback.getCurrentContext();
if (loopbackContext) {
loopbackContext.set('currentUser', user);
}
// This way you can attach memory datasource to model.
// This only covers models defined using app.model();
var models = app.models();
models.foreach(function(model) {
model.attachTo(app.dataSources.memory);
});
next();
});
});
Also use defined datasource, memory in datasource.json.
{
"memory": {
"name": "memory",
"connector": "memory"
}
}
Please refer this too: app.models()