I´m making an angular application, which gives users the possibilities, to manage their projects. I´ve got nodeJS & express serveside and MongoDB as my database.
I want to achieve, that a user can upload media(images under 16MB, so no need to use GridFS) to their projects and that you can display which project, has which media attached.
I´m not getting the images, nor an error. How can I pass the project_Id from angular, to my route, to find the media attached to the project? Is this way of trying to POST and GET the media the right way?
The model for projects and for media:
var mediaSchema = mongoose.Schema({
media : {data: Buffer, contentType: String},
project_id : String,
updated_at : {type: Date, default: Date.now }
});
var projectSchema = mongoose.Schema({
author : String,
name : String,
description : String,
tags : String,
updated_at : {type: Date, default: Date.now },
active : {type: Boolean, default: false}
});
The routing
var Media = require('./models/media.js');
//GET all the media
app.get('/uploads/', function(req, res, next){
Media.find(function (err, media){
if (err) return next (err);
res.json(media);
});
});
//GET one item
app.get('/uploads/media/:projectId', function(req, res, next){
Media.findOne(req.params , function (err, media){
if (err) return next (err);
res.json(media);
});
});
Managing the uploads
app.use(multer({ dest: './uploads/',
rename: function (fieldname, filename) {
return filename+Date.now();
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
done=true;
}
}));
var Media = require('./app/models/media.js');
//POST media to the upload directory
app.post('/uploads/', function(req, res){
if(done==true){
Media.create(req.body, function(err, post){
console.log(req.files);
res.end('File uploaded');
});
}
});
Angular Controller
var app = angular.module('myApp', []);
app.controller('projectCtrl', function($scope, $http) {
$scope.myVar = false;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar
};
$http.get('/profile/project/').then(function (res){
$scope.projects = res.data;
});
//GET Media
var projectId = {{projects._id}};
$http.get('/uploads/media' + projectId).succes(function(data){
console.log('Medien-Daten erhalten');
$scope.media = data;
});
});
Kind regards from Germany,
David
Update (new Errors)
Trying to implement a solution, I get problems with my scopes. When I´m adding the $http.get for the media, my other scope seem to fetch no data... they are shown like this:
Update 2(scope error fixed)
Fixed the error in the controller. I hadn´t defined a var for projectId, that caused the error.
Managed to make the GET request work, and my application is looking for entries in the database. But i can´t manage to see any..
Your use of .find is incorrect in the get all function.
See http://mongoosejs.com/docs/api.html#query_Query-find
Media.find({}, function (err, media){
if (err) return next (err);
res.json(media);
});
This will return all documents.
Related
I am having a 404 issue with my NodeJS API. I don't know if I am quite doing it right, I tried referring to documentation, and I feel like it's close.
MongoDB Schema
var User = mongoose.Schema({
local: {
email: String,
password: String,
handle: String,
pic: {data: Buffer, contentType: String}
}
});
NodeJS UPDATE API
app.post('/api/users', function(req, res, user) {
User.update({email : user.email,
password : user.password,
handle : user.handle,
pic : user.pic},
{$set: {
email : req.body.email,
password : req.body.email,
handle : req.body.handle,
pic : req.body.pic,
done : false
}
}, function(err, users) {
if(err) {
res.send(err);
}
res.redirect('/profile');
});
});
Controller POST API call
$scope.editProfile = function() {
$http.post('/api/users', $scope.editFormData)
.success(function(data) {
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
Any suggestions?
You are not doing a post call correct. You can't pass your post object in the URL. Your node post should look like this.
app.post('/api', upload.array(), function(req, res) {
var body = req.body; //body will be your post object
});
For a post to work you need to make sure you have the proper things added to your Node Project. The above example is using ExpressJS with require('body-parser') and require('multer'). The example you are showing will never show as a true path. For reference here is how you would do a get in node.
app.get('/getcall/*', function(){
// the * denotes any singleton parameter you wanted to pass in.
})
Here are the references I use in all my node projects. These are the basics.
var express = require('express'),
bodyParser = require('body-parser'),
multer = require('multer'),
helmet = require('helmet'),
upload = multer(),
path = require('path'),
request = require('request'),
app = express(),
http = require('http');
Also as for your angular call an $http.post looks like this and you should be using .then instead of .success.
$http.post('/api', $scope.editFormData)
.then(function successCallback(resp) {
console.log(resp.data)
}, function errorCallback(resp) {
console.log(resp)
});
var awsSdk = require('aws-sdk');
awsSdk.config = {
"accessKeyId": "key",
"secretAccessKey": "secret",
"region": "us-east-1"
}
var s3 = new awsSdk.S3({
accessKeyId: 'key',
secretAcessKey: 'secret'
});
exports.awsDelete = function(req, res){
s3.deleteObject({
Bucket: 'bucket',
Key: req.body.photo
}, function(err,data){
if (err) console.log('delete err', err);
console.log(data);
});
};
I can't figure out how to make this work (yet).
initially, I was getting a "no config" error, so I added the awsSdk.config json above. Now, it's just getting hung / pausing with no error. I am getting the expected key in req.body.photo.
My hunch is that i'm missing something in my config..
What am I missing / screwing up?
Update
I've added the code suggested below, but still no luck. I'll show how i'm passing my parameter:
updated code from answer below:
'use strict';
var aws = require('./aws');
var amazon = require('aws-sdk');
amazon.config = new amazon.Config();
amazon.config.accessKeyId = aws.key;
amazon.config.secretAccessKey = aws.secret;
amazon.config.region = aws.region;
var s3 = new amazon.S3();
exports.awsDelete = function(req, res){
var params = {
Bucket: aws.bucket,
Key: res.body.photo
};
s3.deleteObject(params, function(err, data) {
if (err) console.log(err)
else console.log("Successfully deleted myBucket/myKey");
});
};
route:
app.post('/awsDelete', uploads.awsDelete);
Front end Angular:
factory:
angular.module('clientApp').factory('Uploads', function($http) {
return {
delete: function(data){
console.log('delete fired');
return $http.post('/awsDelete', data);
}
};
});
angular controller:
angular.module('clientApp').controller('Distiller-editCtrl', function(Uploads){
$scope.item = {}
$scope.delete = function(){
Uploads.delete($scope.item).then(function(res){
console.log(res)
});
};
});
Seems it 'sort of works'. But something is making it take an extremely long time:
POST /awsDelete 200 120007ms
If I refresh the page, that causes it to successfully delete it as well.
Does anyone notice anything in my code that could be causing such a long response time.
Also, not getting the "successfully completed" console.log
I just tested this in node and it worked fine, obviously you need to put in your own accesskey, secretaccesskey, bucket and bucket key:
var AWS = require('aws-sdk');
AWS.config = new AWS.Config();
AWS.config.accessKeyId = "";
AWS.config.secretAccessKey = "";
AWS.config.region = "us-east-1";
var s3 = new AWS.S3();
var params = {
Bucket: 'test537658ghdfshgfd',
Key: '1.png'
};
s3.deleteObject(params, function(err, data) {
if (err) console.log(err)
else console.log("Successfully deleted myBucket/myKey");
});
Alternatively you can use Minio-Js client library, its Open Source and compatible with AWS S3.
Below is remove-object.js example, you can find complete list here
var Minio = require('minio')
var s3Client = new Minio({
endPoint: 's3.amazonaws.com',
accessKey: 'YOUR-ACCESSKEYID',
secretKey: 'YOUR-SECRETACCESSKEY'
})
// Remove an object name my-objectname.
s3Client.removeObject('my-bucketname', 'my-objectname', function(e) {
if (e) {
return console.log(e)
}
console.log("Success")
})
Please replace YOUR-ACCESSKEYID and YOUR-SECRETACCESSKEY with your own also replace the endPoint to the one you have your bucket is created.
us-east-1: 's3.amazonaws.com',
us-west-1 : 's3-us-west-1.amazonaws.com',
us-west-2 : 's3-us-west-2.amazonaws.com',
eu-west-1: 's3-eu-west-1.amazonaws.com',
sa-east-1: 's3-sa-east-1.amazonaws.com',
eu-central-1: 's3-eu-central-1.amazonaws.com',
ap-southeast-1: 's3-ap-southeast-1.amazonaws.com',
ap-southeast-2: 's3-ap-southeast-2.amazonaws.com',
ap-northeast-1: 's3-ap-northeast-1.amazonaws.com'
Installing Monio-js
$ npm install --save minio
Hope it helps.
Disclaimer: I work for Minio.
so Im currently making an application using MEAN stack. The problem i have at the moment is, when making a call to the API, I am able to successfully retrieve all objects and each object by ID from the database(using POSTMAN(Chrome)) I have set up using mongoose & express router. My question is, can I retrieve an object by it's name ? I have been searching the web and I am unsure how I could implement this. For example: This is the Api code i currently have.
var Dishes = require('../../app/models/dishes');
var Terms = require('../../app/models/terms');
var config = require('../../config');
module.exports = function(app,express){
// api ---------------------------------------------------------------------
var apiRouter = express.Router();
// middleware to use for all requests
apiRouter.use(function (req, res, next) {
// do logging
console.log('Somebody just came to our app!');
next();
});
// Test routes to make sure everything is working
//(accessed at GET http://localhost:3000/api)
apiRouter.get('/', function (req, res) {
res.json({message: 'Welcome to the API!'});
});
/** ================================= Dishes ==========================================**/
//on routes that end in /dishes , show all dishes in json
apiRouter.get('/dishes', function (req, res) {
Dishes.find(function (err, dishes) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err);
res.json(dishes); // return all dishes in JSON format
});
});
//on routes that end in /dishes/:_id , show all the this with the corresponding ID
// get the dish with that id
// (accessed at GET http://localhost:8080/api/dishes/:dish_id)
apiRouter.get('/dishes/:_id',function(req, res) {
Dishes.findById(req.params._id, function(err, dish) {
if (err) res.send(err);
// return that dish
res.json(dish);
});
});
return apiRouter;
};
The dish model I am access is as follows:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//with Mongoose everything is derived from a schema ! Lets get a reference and define our Dishes Schema
var DishSchema = mongoose.Schema({
dishName: {type: String, index: {unique: true}},
Desc : {type: String, index: { unique: true}},
Allergy: String,
HealthRisks: String
},{collection:'Dishes'});
module.exports = DishSchema;
//The Next step is to compile our schema into a model
var Dishes = mongoose.model('Dishes', DishSchema);//Dish Schema into model
// return the model
module.exports = mongoose.model('Dishes', DishSchema)
What I wish to do is make an api call to (/dishes/:dishName) and return the relevant dish. Any help would be greatly appreciated.
apiRouter.get('/dishes/getByName/:dishName',function(req, res) {
Dishes.findOne({dishName:req.params.dishName}, function(err, dish) {
if (err) res.send(err);
// return that dish
res.send(dish);
});
});
I'm trying to write an app that find a city in a MongoDB collection and uses the latitude and longitude it returns to find all zip codes within a certain distance. It seems to work, but the problem is that I'm getting an error that I can't set headers after they've already been sent. However, I've separated the to routes into different requests I don't understand why I'm still getting this error. What is the best way to make multiple calls to the API?
Here is my router in Node/Express:
// route to get city
app.get('/cities/:zip', function(req, res) {
// use mongoose to get the city in the database
console.log(req.params.zip);
var query = City.find({"zip" : req.params.zip});
query.exec(function(err, city) {
if (err)
res.send(err);
res.json(city);
});
});
// route to find cities within 50 miles
app.get('/matches/:latMin/:latMax/:lonMin/:lonMax', function(req, res) {
console.log(req.params.latMin + req.params.latMax + req.params.lonMin + req.params.lonMax);
var matches = City.find({latitude: {$gt: req.param.latMin, $lt:req.params.latMax }, longitude : {$gt :req.param.lonMin, $lt : req.param.lonMax}});
matches.exec(function(err, match){
if(err)
res.send(err);
console.log(match);
res.json(match);
});
});
app.get('*', function(req, res) {
res.sendfile('./public/views/index.html'); // load our public/index.html file
});
Here is my Angular Controller
$scope.update = function (zip) {
City.get({zip : zip}).success(function(response){
$scope.weather = response
}).then(function(response){
$scope.weather = response.data;
})
if(zip.length = 5){
$http.jsonp('http://api.openweathermap.org/data/2.5/weather?zip='+ zip +',us&callback=JSON_CALLBACK&units=imperial').success(function(data){
$scope.data=data;
});
var box = getBoundingBox([$scope.weather[0].latitude, $scope.weather[0].longitude], 50);
City.matches(box[1], box[3], box[0], box[2]).success(function(response){
$scope.matches = response
}).then(function(response){
$scope.matches = response.data;
console.log($scope.matches);
})
}
res.send does not return; the call continues to res.json. And please use braces. Please. Maybe they don't look cool or whatever. Just use them.
if (err) { handleError(res, err); return; }
res.status(200).json(city);
Further down, keeping things DRY:
function handleError(res, err) {
res.status(500).json(err);
}
I'm trying to update a schema using form, however, both on app.put and app.post (which I've seen as a possible solution) i get
PUT https://myapp-demo.herokuapp.com/api/events/5523da4d97c5000300f6e713 404 (Not Found)
and error from ajax callback
Error: Cannot PUT /api/events/5523da4d97c5000300f6e713
on clientside, I make this request:
$scope.saveEvent = function(id) {
$http.put('../api/events/' + id, $scope.formData)
.success(function (data) {
$scope.events = data;
})
.error(function(data) {
console.log('Error: ' + data);
})
};
In express routes, I do this:
app.put('../api/events/:id', function (req, res){
var user = req.user;
var id = req.params.id;
var update = {
$set: {
title: req.body.title,
description: req.body.description,
}
};
Event.findByIdAndUpdate(id, update, function (err, event) {
if(!event) {
res.statusCode = 404;
return res.send({ error: 'Not found' });
}
console.log("event updated");
Event.find(function(err, events) {
if (err){
res.send(err)
};
res.json(events);
});
});
});
I tried to pass event._id differently, by using req.params.id and passing id with form like req.body.id, it all leads to the same result. I've also read about creating hidden input for helping method-override to override form methods. However, having this didn't help.
<input type="hidden" name="_method" value="put">
<md-button class="md-raised md-primary" ng-click="saveEvent(eventId)">Save</md-button>
UPDATE
Indeed, the initial proble was in my put route. I've found a new problem now. When I try to update it again, I get
Error: Object {error: "Not found"}
It happens even after I refresh page or restart server.
The following is invalid:
app.put('../api/events/:id'...
It needs to be in reference to the namespace, or in your case the root:
app.put('/api/events/:id'...