Issue with getting information from mongodb - mongodb

Ok so here is what I am trying to do, I have a Item collection that holds a users items along with price quantity and description. I have also created a collection called soldItems that will store information about a sold item once the user inputs the required data and submits the form. I am not sure if I am doing this correctly to begin with and I have been trying to research this but I don't exactly know what I am looking for.
Here is the code I have so far
router.post("/item/:id", middleware.isLoggedIn, (req, res) => {
Item.findById(req.params.id, (err, item) => {
if(err) {
console.log(err);
}
var soldItem = {
id: req.params.id,
item: req.item.name,
askPrice: req.item.price
};
var soldPrice = req.body.soldPrice;
var soldQuantity = req.body.soldQuantity;
var itemSold = {
soldItem: soldItem,
soldPrice: soldPrice,
soldQuantity: soldQuantity
};
SoldItem.create(itemSold, (err, newlyCreated) => {
if (err) {
console.log(err);
} else {
item.soldItems.push(newlyCreated);
item.save();
req.flash("success", "Item Sold");
res.redirect("back");
}
});
});
});
So... Item.findById(req.params.id) works because I am pulling the ObjectId from the url. However, how would I be able to use req.item._id. Because the issue I am having is when I am trying to get req.item.name and req.item.price I am being told that it cannot read property 'name' or 'price' of undefined. How can I get that information?

Related

MongoDB How to define a query for find an object in array, but the array exist of Object references

Basically what I want to do is that I have an ObjectId of a qr. I want to use that ObjectId to find out which qrBlock does it belong. Im leaving my dbmodel here
so you can track easily.
qrRoute.post("/scanQr", (req, res) => {
let { data } = req.body;
var id = mongoose.Types.ObjectId(data);
Qr.findById(id)
.exec()
.then((qrr) => {
QrBlock.find({ qr: { "qr.$": id } }, (qrblck) => {
console.log(qrblck);
});
});
});
I tried this code above it didn't work.
did you try this way
qrRoute.post("/scanQr", (req, res) => {
let { data } = req.body;
var id = mongoose.Types.ObjectId(data);
Qr.findById(id)
.exec()
.then((qrr) => {
QrBlock.find({ qr: id }, (qrblck) => {
console.log(qrblck);
});
});
});
QrBlock.findOne({ qr: { $all: [qrr._id] } })
this worked for me

How to retrieve currentUser data with Vue.js, AWS Amplify, and MongoDB

I am attempting to build a Vue.js App that synthesizes properties of AWS, MongoDB, and Express. I built an authentication page for the app using aws-amplify and aws-amplify-vue. After logging into the app, metadata containing the username for the logged in AWS user is passed into data object property this.name like so:
async beforeCreate() {
let name = await Auth.currentAuthenticatedUser()
this.name = name.username
}
this.name is then added to MongoDB via Axios:
async addName() {
let uri = 'http://localhost:4000/messages/add';
await this.axios.post(uri, {
name: this.name,
})
this.getMessage()
}
I also have a getName() method that I am using to retrieve that data from MongoDB:
async getData () {
let uri = 'http://localhost:4000/messages';
this.axios.get(uri).then(response => {
this.userData = response.data;
});
},
This method, however, returns data for ALL users. I want to reconfigure this method to ONLY return data for .currentAuthenticatedUser(). In my previous experience with Firebase, I would set up my .getData() method with something like:
let ref = db.collection('users')
let snapshot = await ref.where('user_id', '==', firebase.auth().currentUser.uid).get()
...in order to return currentUser information on the condition that 'user_id' in the collection matches the currently logged-in Firebase user.
To achieve this with MongoDB, I attempted to configure the above method like so:
async getData () {
let uri = 'http://localhost:4000/messages';
let snapshot = await uri.where('name', '==', this.name);
this.axios.get(snapshot).then(response => {
this.userData = response.data;
});
},
My thought here was to try and return current user data by comparing 'name' in the MongoDB collection with the logged-in user stored in this.name...but I understand that this might not work because the .where() method is probably unique to Firebase. Any recommendations on how to configure this .getData() to return ONLY data associated with the currentAuthenticatedUser? Thanks!
EXPRESS ROUTES:
const express = require('express');
const postRoutes = express.Router();
// Require Post model in our routes module
let Post = require('./post.model');
// Defined store route
postRoutes.route('/add').post(function (req, res) {
let post = new Post(req.body);
post.save()
.then(() => {
res.status(200).json({'business': 'business in added successfully'});
})
.catch(() => {
res.status(400).send("unable to save to database");
});
});
// Defined get data(index or listing) route
postRoutes.route('/').get(function (req, res) {
Post.find(function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});
module.exports = postRoutes;
It is not possible to apply a where clause to a uri AFAIK. What you should do is adding a where clause to the actual query you are making in your backend and, to do that, send the username you want to filter the query with through a query parameter like this: /messages?name=JohnDoe.
So basically if you are using a Node/Express backend, as you suggested, and using Mongoose as the ODM for MongoDB your request would probably be looking something like this:
const Users = require('../models/users.model');
Users.find({}, function (e, users) {
if (e) {
return res.status(500).json({
'error': e
})
}
res.status(200).json({
'data': users
});
})
What you should do is getting the username query parameter through req.query and add it to the options in the first parameter of the find function.
const Users = require('../models/users.model');
let params = {},
name = req.query.name;
if (name) {
params.name = name
}
Users.find(params, function (e, users) {
if (e) {
return res.status(500).json({
'error': e
})
}
res.status(200).json({
'data': users.slice
});
})
That way if you point to /messages?name=John you will get the users with "John" as their name.
Edit:
If your backend is configured in the following way
postRoutes.route('/').get(function (req, res) {
Post.find(function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});
what you should do is get the query parameters from inside the get method
postRoutes.route('/').get(function (req, res) {
let params = {},
name = req.query.name
if (name) {
params.name = name
}
Post.find(params, function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});

How to pass id to its associated records with Sequelize

I'm building an app with Express on backend, Postgres for db and Sequelize for ORM.
I have 3 associated models:
Post
Event
Publishing, belongs to Post, belongs to Event
When I publish my Post, I update its state to 2, I need to create an Event and Publishing. Publishing will have the postId and eventId, among other things that I'm passing with a query. I tried the following code, it changes the state of the Post, creates an Event and Publishing, but they are not related to each other.
publishPost(req) {
return new Promise((resolve, reject) => {
async.parallel({
changeState: (callback) => {
Post.findAll({
where: { id: req.query.post_id },
attributes: ['id', 'state']
})
.then((updateState) => {
updateState.forEach((postState) => {
postState.updateAttributes({ state: 2 });
});
})
.then((updatedState) => {
callback(null, updatedState);
});
},
createEvent: (callback) => {
Event.create({
instructions: req.query.instructions,
})
.then((createdEvent) => {
callback(null, createdEvent);
});
},
createPublishing: (callback) => {
Publishing.create({
start_date: req.query.startDate,
end_date: req.query.endDate,
})
.then((createdPublishing) => {
callback(null, createdPublishing);
});
}
}, (error, result) => {
resolve(result);
});
});
}
How can I pass the IDs of the two records to the third model?
There are several problems with your implementation!
First of all, your promise never rejects.
Despite of that, you don't actually need to create a promise or use async for this, neither do you want them to run in parallel: If creating a Publishing record needs information about the Event, then you'd want to create first the event, so that you have its id, THEN pass it in the input for the publishing.
Another important thing, take a look at this piece of code:
.then((updateState) => {
updateState.forEach((postState) => {
postState.updateAttributes({ state: 2 });
});
})
.then((updatedState) => {
callback(null, updatedState);
});
Inside the first then, you are making multiple updates, which are promises. They will be dispatched and you never get their values back. Let me explain:
Think if you have just one update to make. It would be like this:
.then((updateStates) => {
return updateStates[0].updateAttributes({ state: 2 });
})
See, we are returning a promise (in this case the update), so the next then will only be called when the update resolves.
If we do this:
.then((updateStates) => {
updateStates[0].updateAttributes({ state: 2 });
})
It will dispatch the update (which takes time) but because you didn't return it, it will pass through and return nothing. Check this out:
var promise1 = new Promise(function(resolve, reject) {
setTimeout(function(){
resolve('foo')
}, 2);
});
var promise2 = new Promise(function(resolve, reject) {
setTimeout(function(){
resolve('foo2')
}, 2);
});
promise1
.then(function(result){
promise2
})
.then(function(result){
console.log(result) //will print undefined
})
promise1
.then(function(result){
return promise2
})
.then(function(result){
console.log(result) //will print foo2
})
So, you are calling multiple updates without getting their values back; if they fail, you'd never know.
Just one more thing: if something goes wrong along the way, you probably want to rollback all the changes made so far, for that, you should use transactions.
Maybe you should try something like this (not tested):
return Post.sequelize.transaction(function (t) {
Post.findAll({
where: { id: req.query.post_id },
attributes: ['id', 'state']
})
.then((updatedStates) => {
var promises = []
updatedStates.forEach((postState) => {
promises.push(postState.updateAttributes({ state: 2 }, {transaction: t}));
});
return Promise.all(promises);
})
.then((results) => {
return Event.create({
instructions: req.query.instructions,
}, {transaction: t})
})
.then((createdEvent) => {
return Publishing.create({
post_id: req.query.post_id,
event_id: createdEvent.id, //or event_id, depends on your model
start_date: req.query.startDate,
end_date: req.query.endDate,
}, {transaction: t})
});
}).then(function (result) {
// Transaction has been committed
// result is whatever the result of the promise chain returned to the transaction callback
}).catch(function (err) {
// Transaction has been rolled back
// err is whatever rejected the promise chain returned to the transaction callback
});

How to stop inserting duplicate records before saving in db?

I'm trying to save students records, but it should not take duplicate records. How is it possible? In below code i have tried to do
app.post("/save",function(req,res){
var std=new student(req.body);
student.findOne({},function(err,success){
if(err)
{
console.log(err);
}
else
{
// console.log(success);
std.save(function(err,success){
if(err)
{
console.log(err);
}
else
{
console.log("inserted");
console.log(success);
}
});
}
})
});
Here is the sample code. Please note that the existence of the value in MongoDB database depends on the req.body as mentioned in the OP.
In the below code, I have only name attribute in the Student collection. So, the duplicate check is based on the name attribute only.
You may need to change the code if you would like to check for the specific attribute in the collection to determine the duplicate value.
Please note that my Student collection has only attribute in the schema as well.
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Student = mongoose.model('Student', { name: String });
var app = express();
var bodyParser = require('body-parser');
var app = express();
var urlencoded_body_parser = bodyParser.urlencoded({
extended: true
});
app.use(bodyParser.json());
app.use(urlencoded_body_parser);
app.post("/save", function (req, res) {
console.log(req.body);
var student = new Student(req.body);
Student.findOne(req.body, function (err, success) {
if (err) {
console.log(err);
res.send(err);
}
else {
console.log(success);
if (success == null) {
student.save(function (err, success) {
if (err) {
console.log(err);
res.send(err);
}
else {
console.log("inserted");
console.log(success);
res.send("success");
}
});
} else {
res.send("Student already present");
}
}
})
});
app.listen(3000);
Output:-
First time execution:-
Input:-
{
"name" : "john"
}
Output:-
success
Subsequent executions with the same input json:-
Output:-
Student already present

REST Routes with mongoose and express

When I try to add a review to my product from the front-end I am getting a 404 error for PUT http://localhost:3000/products. But I am to add/update data using the following curl command using my routes:
curl --data "name=Product 1&description=Product 1 Description&shine=10&price=29.95&rarity=200&color=blue&faces=3" http://localhost:3000/products
My products router
// This handles retrieving of products
// Includes Express
var express = require('express');
// Initialize the router
var router = express.Router();
var moment = require('moment');
var _ = require('underscore');
var color = require('cli-color');
var mongoose = require('mongoose');
var Product = mongoose.model('Product');
var Review = mongoose.model('Review');
// Route middleware
router.use(function(req, res, next) {
console.log("Something is happening in products!!");
next();
});
// GET route for all Products
router.get('/', function (req, res, next) {
Product.find( function (err, products) {
if (err) {
return next(err);
}
res.json(products);
});
});
// POST route for adding a Product
router.post('/', function (req, res, next) {
var product = new Product (req.body);
product.save( function (err, post) {
if(err) {
return next(err);
}
res.json(product);
});
});
// Pre-loading product object
router.param('product', function (req, res, next, id) {
var query = Product.findById(id);
query.exec( function (err, product) {
if (err) {
return next(err);
}
if(!product) {
return next(new Error('can\'t find product'));
}
req.product = product;
return next();
})
});
// GET route for retrieving a single product
router.get('/:product', function (req, res) {
req.product.populate('reviews', function (err, product) {
if (err) {
return next(err);
}
res.json(req.product);
});
});
// POST route for creating a review
router.post('/:product:reviews', function (req, res, next) {
var review = new Review(req.body);
review.product = req.product;
review.save( function (err, review){
if (err) {
return next(err);
}
req.product.reviews.push(review);
req.product.save( function (err, review) {
if (err) {
return next(err);
}
res.json(review);
});
});
});
This code is taken from a tutorial on thinkster for [MEAN stackl2
Original Post
I am having trouble figuring out how to update an existing entry in my mongodb database using a service I defined with ngResource in my Angular app. So far I have been unable to create a function that will update the back-end after a user clicks my submit button. I have been looking around for a solution for about 2 days but so far have not found a solution. I know the solution is similar to how I delete users in My User's Controller, but nothing I have tried has worked.
My Product Service
angular.module('gemStoreApp.productService',['ngResource'])
.factory('productsService', function($resource) {
return $resource('/products/:id', {},{
'update': { method: 'PUT'}
});
});
My Product Detail
angular.module('gemStoreApp')
.controller("ReviewCtrl", ['$scope', '$resource', 'productsService', function ($scope, $resource, productsService) {
this.review = {};
this.addReview = function(product){
product.reviews.push(this.review);
productService.save({id: product._id}, function() {
// I have tried .update, .$update, and .save methods
});
this.review = {};
};
}]);
I have verified that the products.review variable contains the update. Here is a sample of my JSON output from my console before and after adding the review:
Before the review is added to the front end
{"_id":"product_id","name":"Product 1","description":"Product 1 Description",...,"reviews":[{}]}
After the review is added to the front end
{"_id":"product_id","name":"Product 1","description":"Product 1 Description",...,"reviews":[{"stars":4,"body":"An Awesome review!","author":"user#domain.com","createdOn":1436963056994}]}
And I know that my productsService.save() function is being called as well, as I can put a console log in and see it run when I view in the browser.
My User's Controller
angular.module('gemStoreApp')
.controller('UsersCtrl', ['$scope', '$http', 'usersService', function ($scope, $http, usersService) {
$scope.users = {};
$scope.users = usersService.query();
$scope.remove = function(id) {
var user = $scope.users[id];
usersService.remove({id: user._id}, function() {
$scope.users.splice(user, 1);
});
};
}]);
My full source code is available on my Github page. Any help will be greatly appreciated.
I actually put it into work in this plunker
Took the same factory :
app.factory('productsService', function($resource) {
return $resource('product/:id', {id:"#id"},{
'update': { method: 'PUT'}
});
});
here is my controller :
$scope.products = productsService.query();
$scope.saveProduct = function(product){
product.$update();
}
and how i pass the value in the HTML :
<div ng-repeat="product in products">
<input type="text" ng-model="product.text">
<button ng-click="saveProduct(product)">Update</button>
</div>
If you track the networks request in the javascript console you will see a request : PUT /product/id with the updated data.
Hope it helped. If you have anymore question fell free to ask.